3 ms·
Type checking allows the compiler to prove certain properties hold for your code, and so this can be used to catch certain classes of bugs. Unit tests don't hav
by danielam 3y ago
Type checking allows the compiler to prove certain properties hold for your code, and so this can be used to catch certain classes of bugs. Unit tests don't have that power. But which classes of bugs are caught depends on the type system. Not all type systems are the same. In most statically typed languages, division is not total, and so a function using division can type check, but also crash the program at runtime. In such cases, unit tests can complement types, so you can profit from both. Furthermore, in most languages, the type system is too coarse to prove the sort of correctness that unit tests try to corroborate. If types are a specification, then a sorting function with the type signature `[Int] -> [Int]` doesn't tell us much. There are, in principle, an infinite number of functions that have that type, most of which are not sorting functions. Unit tests can give us some modest, practical confidence of correctness that such a type system cannot. On the other hand, dependent types do permit us to construct return types that guarantee that some ordering relation holds, so it is possible to make the specification more precise in such cases. Such precision may not always be economical or easy to achieve, however. Type inference can assist us in this task, though.
But one of the aspects of types that I find useful is the documentation they provide. In a dynamic language, you often have to guess what the types of functions are by reading the implementation, and not just of the function in question, but the functions composing that function. As a code base grows in size, this can become annoying. With code base size, modularity becomes increasingly important, and modularity benefits greatly from clearly defined and stable interfaces. Also, types can enable something like LSP to make suggestions about what can appear in a given place. With type inference, this can be quite powerful, allowing you to build code in an interactive fashion (proof assistants make use of this behavior).
Unit tests can also provide value as documentation, in the sense that they can function as tested and working examples of, say, how a library could be used.
So, in other words, both types and unit tests have value, and the value they offer will vary depending on the type system and how types are being leveraged in a given situation. There exists an overlap in the practical value provided by types and by unit tests, and where there is overlap, I would say types have the upper hand in principle, if not always in practice.
- magicalhippo 3y ago> But one of the aspects of types that I find useful is the documentation they provide. For me this is one of the core aspects. Self-documenting code makes me so much more productive, and being able to reason about code thanks to the types without having to consult the documentation is very powerful. Any time I work with JavaScript, Python or similar I invariably waste time having to do print(dir(foo)) or similar, just to figure out what the hell some function returned and what I can do with it.
- monocularvision 3y agoThis is the most well thought out commentary on this topic I have ever read. Thank you.