3 ms·
Type systems exist on a spectrum. A rich type system is better at documenting your code than comments are if the compiler and it's type system are sound: the co
by agentultra 7y ago
Type systems exist on a spectrum. A rich type system is better at documenting your code than comments are if the compiler and it's type system are sound: the comments can be wrong, the types cannot.
A sufficiently expressive type system can check your logic for you. Push as much of your propositions and predicates into the types as possible.
Data types are better than exceptions, return codes, etc for the majority of unexceptional cases. Conditions and restarts are better than exceptions. Sometimes crashing is not an option when your computer is flying in the air with a human.
In addition to specifications -- often a bunch of boxes with arrows will not be sufficient. There are a range of tools to check your designs from automated model checking to interactive proofs. When the problem is difficult to understand on its own then the solution is probably even harder -- a good sign you should consider using one of these tools to make the problem clear and guide you to the right solution.
- JamesBarney 7y agoI agree with everything you said, except >: the comments can be wrong, the types cannot. If you're arguing comments are valuable but type constraints are a better way to express requirements than I agree and sorry for the long post. But I've seen a lot of comment hate on hackernews and I feel like I have to defend comments. I really think comments can be especially valuable. They're valuable when reviewing code because they tell the reader what the developer was attempting to do, not necessarily what they did. Not everything is expressible in every type system. Even something as simple as "this reference can't be null" isn't expressible is many languages. Comments are easier to read than type names, a sentence is much more expressive than code. Especially code that is tricky due to performance or domain complexity. Type and method names can rot too. If you have a method that starts with get that someone adds a little bit of updating logic to making the method name misleading. And comments can be kept up to date easily by just adding an item to your code review checklist "Ensure comments match code".
- agentultra 7y agoComments are useful and type constraints are a better way to express specifications. It varies on the level of expressivity and soundness of the type system employed as to how valuable comments are. In my experience there's an inverse relationship: the more expressive the type system, the less valuable are comments. This is true in so far as the types get richer the more they can express with less ambiguity than prose. In a way this makes the comments that do exist in such a code base even more valuable since they describe far less and are probably filled with interesting information such as why certain propositions are important, etc. However when you're working in languages without a static type system or a rather weak one, comments can be necessary and invaluable. Update To clarify, in a type system as rich as a dependently typed language, given an inductive definition of vectors, and a type; Agda, for example, can often find the solution (the term) that implements the type. You could add a comment if you wanted to but you'd only be elaborating on what is already obvious by the type signature. This does scale beyond trivial examples such as vector products and into the realm of business logic; it's possible to encode state machines this way. Code comments of this kind of code end up looking superficial. In a more common FP language like Haskell, often derided (even by me) for it's lack of commenting and documentation, seems to be that way precisely because once you get used to understanding how to reason about types... well it gets redundant... and the compiler cannot check that comments are correct with respect to the term level code. The comments are sparse and rich instead of redundant and full of exposition. That's not to say that comments don't exist! Other poster have given many good examples where they are definitely necessary. I ascribe to the rule that there's a balance and too many comments are not helpful just as too few are as well.
- brianpgordon 7y agoI'm on team comments too. The article puts it well: > When you start the code by writing the documentation, you're actually making a contract (probably with your future self): I'm saying this function does this and this is what it does. > If later you find out that the code doesn't match the documentation, you have a code problem, not a documentation problem. "Self-documenting code" is, in my opinion, a silly canard. Maybe it's appropriate for some brain dead glue logic or frontend boilerplate, but any time you really need to think about what the code is doing, a comment will be immensely helpful. I don't at all buy the argument that comments too easily get stale. They won't get stale if you maintain them.
- gregmac 7y agoHonestly, there's very little code where comments on the function calls can't be helpful. Let's use GetUserDetails(userId) A comment like "gets the details about a user" is of course a waste of time. What I like to see is everything about using it, without having to read the code. For example: "Gets details for a user, based on the Service.CurrentUser access rights. If userId doesn't exist, is not available valid id, or the current user diesn't have permission, throws exception. Note this can return data for disabled and deleted users, so if used for non-admin functionality, you should check the State property. Due to caching, this might not show changes made in another session in the past couple minutes." The lack of a check for disabled status (for example) won't be obvious if I'm not actively thinking about checking disabled status. That few seconds of a comment can easily prevent a bug when someone consumes this - especially if they didn't write this API or are new to the cosebase (maybe they don't even know disabled users are a thing). Sometimes when you write these types of comments you realize your naming is bad, or that there's an API change that would make it easier to avoid a mistake - such as having separate GetActiveUserDetails() and AdminGetUserDetails(). I think about this during vice reviews, too: I've often asked for comments to be added on existing methods being consumed (but not modified in the code I'm reviewing) because the new use made me wonder about how something would be handled and I had to go read a couple levels deep to figure it out.
- agentultra 7y agoAgree. And in a richly-typed language you can be more specific: getUserDetails :: UserID -> DBAction (Maybe AnyUser) This type says a lot already. The definition of `AnyUser` would specify the parameters that the comment only says in prose. Or we could be more specific getActiveUserDetails :: UserID -> DBAction (Maybe ActiveUser) We could also include the authorization specification in the type constraints on the `DBAction`: getUserDetails :: (DBAction m, HasAdminContext m) => UserID -> m (Maybe AnyUser) This is what I mean when I say that a rich type system can enforce a lot of what you might traditionally use comments for in a weaker type system. Now my hypothetical comment might highlight some salient points about this function, such as performs N queries to validate all of the available authorization contexts, use with a user role that has a limited number of contexts for best performance.
- mannykannot 7y agoOf course, if a compiler and its type system are sound, then the fact that certain errors are eliminated follows trivially, but, in practice, this does not prevent types (and especially those of the rich type systems you are advocating) having bugs in their implementation. Take, for example, floating-point numbers in Excel. Even something as fundamental as floating point types need documentation, which is why we have IEEE 754.