Dynamic typing is good
Dart and TypeScript introduce optional static typing, which is then used in every example. It makes me feel troubled. Are they implying that all production code should always be statically typed? Probably no. Is someone getting that idea?
You might add type labels into your programs for following reasons:
- Eliminate wide range of bugs caused by mistyping and logical errors.
- Use IDE with code completion taking advantage from strict types.
- Produce optimal code.
Despite these reasons, you should never introduce type labels into your program where they do not provide valuable cues or shave off seconds from an actual benchmark. If you strictly type label your source code then you're not writing most readable code you could. And that's terrible.
Source code is meant to be read and reasoned
Programming languages are designed to close a gap between smart people and computers. So computers can read something people can easier reason about. It's easier to reason about behavior of complex binary relations when they are in math notation. Likewise for same reason structured programs are restricted to single entry point for every line. Computers would be entirely happy if you gave them bunch of instructions crammed together and separated by whatever your instruction set architecture gives.
It's not a coincidence that such abstractions make programs easier to read. Abstraction separates ideas from things irrelevant for the idea alone. The C source code describes the same thing as the assembly program, except those things you can ignore. This makes source code in C easier to reason about compared to assembly listing. Being able to reason about your program is so important that efficiency has been sacrificed many times to reach it.
Static typing, introduced by Dart eliminates type and typing bugs. Logic bugs are when the program isn't useful or fails to function despite compiling. A good way prevent and fix logic bugs, is to be able to reason about the program. For this reason readability is many times more important than being able to eliminate certain classes of bugs or having a helpful feature in the IDE.
Maintainability in software projects
People love to talk about maintainability when discussing type systems. It's lovely way to say that your language is better, especially if it's not clear what the term means. It's very complex term so it can be anything if not bolted into something rigid.
Wikipedia states that maintainability in engineering projects mean certain ways to extend usability and maintenance of the item in question. In other hand, Wikipedia's software engineering article for maintainability looks like a bingo sheet, so we are probably better off applying the engineering points with programming. They would look like this:
- isolate bugs
- replace faulty part of the program without having to replace working parts
- suspend damage caused by bugs
- maximize software reliability
- meet new requirements
- make future maintenance easier
Rigorous labelling of your types are only capable of isolating bugs. Ability to reason about your program covers all of them. There's no way that static type checking would eliminate the need to reason. We already made it clear that losing readability hampers your ability to reason about the program. Now you only need to know that unthoughtful type labeling breaks readability, and it's clear that it hurts maintainability.
Stating the obvious adds nothing of value
Consider the following program that reads from a file descriptor:
int fd /* four kilobytes is standard page width on linux */ size_t count = 4k /* allocate from stack */ char *buf = alloca(count) /* read from file descriptor */ read(fd, buf, count)
You can see here that comments actually make it harder to reason about what the program is doing by simply adding redundant noise into the description of the program. That's because everything is said twice, as if the code alone were too unreadable to stand by it's own. Let's remove those insults:
int fd size_t count = 4k char *buf = alloca(count) read(fd, buf, count)
Now this is much more readable if you know what
read means. If
you are qualified to change and reason about this line then you know those things
anyway, or went to find out what they mean. But if you look at this now, aren't
the type labels here also redundant? 4k is obviously an integer.
returns a buffer of memory. Here's the code without type labels:
count = 4k buf = alloca(count) read(fd, buf, count)
Of course, it's not just the redundancy that hampers readability. Consider what happens if I insert an irrelevant comment in the middle:
count = 4k buf = alloca(count) /* I ate feta cheese for breakfast while I was writing this code. */ read(fd, buf, count)
Sometimes describing type of the variable is irrelevant to it's surroundings, alike describing your diet in the comments. Although it might be interesting to know it still distracts the reader from the relevant. It's not only possible with comments to describe irrelevant. You've probably seen this kind of code somewhere:
count = 4k buf = alloca(count) launch_nukes() read(fd, buf, count)
I hope it was not an industrial production quality code, one that you revere. If you keep repeating and remixing yourself like a parrot, you're obviously an idiot. Therefore mandatory static typing is an obviously idiotic property in a language.
Don't get me wrong about the comments. Surely there exist good comments too. They tell useful things that aren't obvious from reading the code or the reference manuals. It might answer where, or why the code is there. For similar reason it's a common best practice to write constant variables instead of magic numbers so the name described what the number means.
For these reasons, when writing teaching material, you should never use comments to describe what the code is doing. Get some other method to do that. It easily gives the wrong idea of how to properly use comments. Be a good example!
Type checking can hide bugs
Before, I mentioned there are many kinds of bugs. Being incompetent and having no clue of what you're doing is one of them. Sure you probably love challenges if you are supposed to become great programmer. Also you should go to solve hard problems to become better at it. It's poisonous only if there's a deadline issued by somebody else. Say you have three months of programming experience and task that challenges a veteran. Boss said you have to solve it before midnight.
Certain classes of bugs are connected. You probably understand this. You called for
brains instead of
grains, or you might multiply something together when you were
supposed to subtract. It's common to mess up with precedence rules so some programmers
prefer to avoid some complex precedences altogether. Sometimes simple bugs are symptoms
from a more complex bug. Such as being incompetent.
Now lets say some program just broke and doesn't compile anymore. Put the programmer, who's still confused about loop constructs, to fix it. He gets to correct each of the bugs one by one, not understanding what the code means or how he's fixing the bugs. After long waiting all the compilation bugs end up eliminated. It looks like he succeeded because the code runs now. Nobody will figure out that his contribution was in fact negative because he only eliminated the cues of the bugs.
Type checking allows you to manage code that isn't mentally maintainable. The sort of code that you can't reason about. The broken codebase gets extended by inserting line here and there. The type checker provides just enough correctness that it holds up. You might even think that it's "type safe" and reason yourself to test less often. The type checking and optimizations take so much time anyway that you wouldn't test code often anyway.
Because static type checking keeps nagging you, it might be that even as professional you're carelessly fixing bugs that might turn out to be valuable cues later. Program that's in development doesn't need to be correct because it's not for production yet anyway!
Best maintainable code might, in fact be, dynamically typed.
I tried to find some research about the static types and maintainability before posting and found some empirical studies. They are pure fiction with fictious data isolated carefully from any real situation. Their results are difficult to compare or analyse. The test samples are small because there's too few test subjects available. The problem seems to be that they are empirical studies in the first place.
To be fair, I asked from bunch of places and never found any supportive evidence for or against static typing maintainability. I have only my experience and wit to stand behind my arguments.
Do Static Type Systems Improve the Maintainability of Software Systems?
This paper States that static typing is beneficial to maintainability. It makes an arbitrary pick of groovy and compares it to java. The author believed the subjects were proficient with java. Proficiency with Groovy was assumed and it was picked because "it's dynamically typed java". The test was done with expectations that static type systems are helpful in programming.
The guinea programmers were given tasks sequentially with executable tests that determined whether the code is correct. Whenever the executable test passed, the program was implied to be correct and the another task was given. Correctness of the program was not measured otherwise.
There were only handful of test subjects and the source code was small, around 1300 lines. The mean time to solve a task was around 10-15 minutes, fastest programmer solving each problem in 2-5 minutes. The length of the test was 1-4 hours. The authors were award-winning academics.
So in short, nothing about maintainability was really tested here.
An Experiment About Static and Dynamic Type Systems
This paper claims that static type system has not negative or positive impact on application's development time. The author questioned such starting situation as in previous paper - the choice of java programmers to test everything. 49 subjects were picked from undergraduate students. He asked them to write a simplified parser for java. Each group was trained in the languages written for the experiment. After they were trained, they had 27 hours to implement the parser. There were lots of test cases, and the quality of the test was measured as percentage of successful test cases.
I described them because they're funny studies. Too bad they do not mean what their authors believe.
For language designers
If you do not have capability to understand what I just told you here, you aren't ready for designing a new programming language. Work on something else first. Revise your beliefs about benefits of static typing.