6 ms·
> Do I agree that there will always be semantically wrong bits of code that can't be detected by a compiler (whether as part of a type system or otherwise)? I'm
by vilya 15y ago
> Do I agree that there will always be semantically wrong bits of code that can't be detected by a compiler (whether as part of a type system or otherwise)? I'm not sure I do.
Here's a very simple counterexample that I don't believe it's possible for a compiler to detect: writing a - b when you should have written b - a. More generally, that applies to any non-commutative function which takes two arguments of the same type.
This is also a good example of where a coding convention could help: if those variables had been named more descriptively it would have been much easier to see which way around they should go.
- ajanuary 15y agoI'm sure I'm just missing something, but I'm struggling to come up with a reasonable case where you couldn't just have a and b be different types and provide an operator for typeof a - typeof b but not typeof b - typeof a (or vice-versa). Of course, that would upset Joel on account of not knowing what - did without knowing the types.
- masklinn 15y agoDepends what you mean by "reasonable" I'm guessing. Manually encoding a semantic analysis would have a very high overhead, and you might be able to do it via dependent types instead (not sure though, they tend to hurt my brain when I try to actually understand them), but I don't think they're considered practical (yet).
- vilya 15y agoJust because you can, doesn't mean you should. :-) Forcing a and b to be different types could cause a different problem - maybe a worse one, depending on how many subtractions your code requires.
- JadeNB 15y agoIt's maybe not very realistic, but you'd have trouble with this approach if you were trying to code the distance function `(a, b) \mapsto |a - b|` in a language that didn't have an absolute value.
- yummyfajitas 15y agoThis is also an error which cannot, as far as I know, be detected by any coding convention. I'd suggest that if you are trying to prevent such errors with a coding convention rather than tests, that's a process smell. In practice, I find it best to avoid non-commutative functions with two arguments of the same type. The obvious choice (for a DB I'm writing): addRecord :: ByteString -> ByteString -> IO Bool addRecord key value = do ... But this is safer: addRecord :: DBKey -> DBValue -> IO Bool Now `addRecord value key` won't compile.
- sophacles 15y agoIt is arguably a coding convention to say "make new types and appropriate conversions to help ferret out errors, even when they are just aliases to existing types". I see what you are doing here as fundamentally the same trick that the OP article does, albeit with some nice static analysis thrown in to help.
- vilya 15y ago> This is also an error which cannot, as far as I know, be detected by any coding convention. I'd suggest that if you are trying to prevent such errors with a coding convention rather than tests, that's a process smell. Coding conventions don't detect errors, they just help to make them more obvious. For instance, if the variables had been named "cake" and "slice", it probably would have been a bit more obvious which side of the '-' sign each one should be on. In any case, it's not an either-or choice between coding conventions and tests. A sensible developer will have both. > In practice, I find it best to avoid non-commutative functions with two arguments of the same type. I guess there's a silent "..where possible" attached to that? :-) There are many times where it's not possible, or at least not sensible; and having too many type conversions in your code can be just as bad for readability as having too few.