I went Java, Prolog, NetLogo, Haskell within one year of uni, learning C++ soon after. That may have been why I've never really considered a programming language's syntax hard to learn. Ecosystem, documentation and day-to-day use, now that's a different story.
Typing doesn't cover your back... it wastes your time actually.
TDD does cover your back ;)
Typing saves a lot of time, as it allows for much easier, and more extensive refactoring. Because your first version will never be the final version, you will need to refactor time and time again
This is most certainly not a black-and-white issue.
It's not just the language, but how it fits our various brains.
Exactly... I used to C# before, and after I used python I see why typing isnt my friend anymore.
I just do proper tests and grow my apps super fast.
While you code your brain types code anyway, as in “I expect this argument to be a string, the next one is an integer etc.”
I have no strong preference on dynamic vs static typing, there are lots of languages I like in both camps.
However, types always get specified one way or another, either during compile time or adhoc during tests and runtime.
I agree that older type systems feel more of a burden than actually useful, but the same cannot be said for Haskell, Elm or Rust.
This is the problem with C-like languages. It is a different story with ML languages. With ML languages you do not spend much time writing types because of type inference. On the other hand, you have more guarantees about the absence of errors if compiles. I write series of posts about types to show practical side of type systems dev.to/t/pragmatictypes
Others have already posted comments defending their subjective love of type systems. But there is an objective observations I would like to add:
Using a good type system, you can prove your program's correctness on type level, because it makes writing a program the same thing as formulating a mathematical proof.
With a test, all you have is a sample. If and only if your code is pure, such a sample proves you that your code works on the sampled input.
Of course (human) testing has its own strengths; for one, it can find problems in the algorithm itself rather than its implementation.
As a practical example of the value of typing (with monads) I'm going to point to the obvious NoRedInk example.
Hmm... I agree on type level correctness with you.
But, this goes onto the critical issue with TDD, most people misunderstand it and tend to talk about the code coverage metrics where it all got wrong.
Suppose you do TDD on the business rules metrics and 99% of them are well tested, meaning all the behavior your code is correct (from the business perspective)... would you really care about type level correctness?
As for the NoRedInk example, this got to do also with the TDD and it's an exceptional case IMO.
People tend to test JS frontend code, and what is JS mostly doing? it manipulates the DOM / BOM... UI stuff.
Basically UI testing is glue testing, you change the UI tomorrow, and you gotta change the tests too. It's like testing 1 + 1 = 2.
That's where elm typing is really great, you don't need to test UI, however you verify what you're doing with typing ;)
I think the necessity of strict typing correlates with fast prototyping vs scaled up core code.
For startups with quickly growing projects, TDD + a dynamic language is a very good way to stay fast and agile. But I've noticed that eventually you hit a point where you really want to rewrite core functionality in a stricter language to reach specific levels of safety which are extremely tedious to achieve with dynamic typing + TDD.
With Haskell, the type system is so good, that I've found that tests often don't even make sense — the type signature is pretty much guarding (and documenting) exactly what the function does.
Now that everything from python to PHP has typehints and JS has several typed dialects, I'd say: use them! You'll notice that they're going to save you in places where you thought tests were perfect.
There is a reason larger companies have come up with languages like Go, Typescript, Flow, Rust, Dart, HHVM, etc — they noticed dynamically typed code doesn't scale to the levels they needed.
I think optional typing introduced in Python 3.7 is a great addition. Like you, I now want to go back to some core elements and add stricter rules
There are ways of adding types to untyped Python code like google's pytype (static), monkeytype(dynamic) or some other library that randomly generates values into functions, runs thems, and sees what errors happen... However, at least monkeytype (its based on intercepting function calls and assuming that if you call a function with a list it must take a list object, but thats wrong because you can use any sequence). There was a talk where someone built one that randomly injected mock objects into code and given a type-inference algorithm would get the most general type (dynamically), I need to google that again, I tried building one myself too...
Python has optional typing with mypy and its annotations though, but I'd go for tests first not types and maybe generate the types from the tests : ). Tests can't check every code path like types, but they catch more errors overall and they are a better form of documentation.
which is easier to understand:
filter(pred: Function[A]->Boolean, seq: Sequence[A]) -> Sequence[A]
% isOdd = lambda: x % 2 == 0
% list(filter(isOdd, range(0, 6)))
[1, 3, 5]
The unit test which is the same as replacing the types with actual values, can tell you more about the function because it actually tells you what the function actually does, and the types just tell you that you take in a Sequence and return a Sequence while the example test tells you that the return value is a subset of the sequence and that it uses the pred function to create that subset. You can generate the types from the test values BTW, and its easier for someone to generalize values to types than the opposite. Also types give you a false sense of security, and they can't check that you wrote your filter function correctly because all they care about is the domain of the values not what the function ACTUALLY does.
You're making the comparison by using the most useless example of types imaginable. For a fair comparison you'd be using at least Elm's type system, but preferably Haskell's or even Agda's.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.