To me, the catch phrase “if it compiles it works” is a very real thing. The system you code against gives you friction, and in return you get benefits/garanties. Is worth it? Only the programmer can tell.
I get this feeling even more when coding with Haskell, although I’m only learning and scratching the surface here.
I don’t think any programmer would ever assumed a programming language could protect you from logic bugs
“You’ll get less runtime errors” is probably more accurate, but even then…
I’ll give you a couple of examples.
This Java code compiles fine and will fail at runtime with a NullPointerException:
package org.example;
class Hello {
Integer counter;
public Hello() {
}
void sayIt() {
counter++;
System.out.printf("Hello world! (%d)", counter);
}
}
public class Main {
public static void main(String[] args) {
Hello hello = new Hello();
hello.sayIt();
}
}
Golang chose to ignore these kinds of problems by enforcing default values (an uninitialized string is “”, an uninitialized int is 0, etc.)
Personally, I found this to be not a good solution because the concept of “nothingness” is still useful/required for database work. This forces you to deal with pointers to express nothingness and you’re back at square one.
TypeScript’s type system can actually lie to you and I see that googling “TypeScript lie” returns a few interesting blog posts.
Anyhow, all these little things add up, and it’s quite refreshing to have a sound type system giving you the feeling that:
If it compiles, it (probably*) works
P.S. I’m pretty sure I’ll find a few warts with OCaml along the way, but then again, at this stage, I’m pretty sure I’ll find less of them compared to other languages.