First, if you're writing any kind of big code, than somewhere, in your code base, someone else is writing a code where the user name is spelled `username`. Or `user`. You don't have to be "asleep at the wheel" to not remember, or not know, which is which. So you're going to type the wrong one (not necessarily on purpose), and you'll get a runtime error. Not that bad, sure, but you'll get it.
Also, at some point, you'll realize that a string is not the ideal way to represent a user name [1], and some of the functions that deal with users are going to start returning a Struct %User{first_name: ..., middle_name: ....}. Or will it be a Map %{"first_name" => ...} ? And surely you're going to track all the calls of `foo` to fix them. And all the calls of all the calls of `foo`, because, who knows ? And suddenly you're doing the mental job of a static type checker. Surely you're not "asleep at the wheel" anymore, because you're doing the work of the wheel by manipulating the gears by hand.
Bottom line: I'll gladly admit that I'm too old and stupid to do that anymore. I had typechecking in the 90s. Give it back.
So you're going to type the wrong one (not
necessarily on purpose), and you'll get a runtime
error. Not that bad, sure, but you'll get it.
I agree with your facts but not your conclusion here. This certainly happens, but this is trivially caught by your integration tests.
Now, it's certainly true that in a static language, your compiler would catch this for you. In a decent IDE it would be pointed out to you while you type.
However, static or dynamic, you're going to be writing tests anyway, so I can't view this as some sort of increased burden when it comes to writing tests.
Also, at some point, you'll realize that a string is not the
ideal way to represent a user name [1]
I have loved that article since it came out! It's one of those things I saved as a PDF just in case the original goes offline someday.
I don't think your examples are realistic, at all, though.
1. If you replace `User#first_name` and `User#last_name` with `User#name` (which returns a `Name` object) your test suite is going to blow up all over the place every time you call the deleted `User#first_name` or `User#last_name` methods anyway. And now you have a list of places where you need to fix your code.
2. But, what if you update the internal structure of `Name` over time? Some of the above applies. But also callers of `Name` shouldn't know too much about `Name` anyway - it should be providing some kind of `Name#display_name` or whatever function that handles all of the complexity and returns a dang string anyway.
Everything I've written here presumes the existence of a test suite, of course. Which of course takes time to write and maintain. But any nontrivial project needs one anyway regardless of language or type paradigm, right?
Bottom line: I'll gladly admit that I'm too old and
stupid to do that anymore. I had typechecking in
the 90s. Give it back.
Absolutely the same here. But, I seem to miss it in different places than you.
I miss static types when I'm writing code. I want my IDE to tell me the types and type signatures when I type, and draw a little squiggly line under my code when I get it wrong. In Ruby, I wind up having 10 different files open at a time in my text editor so I can see what various methods are expecting.
This is mitigated somewhat by simply bashing out a lot of my code in irb/pry directly, since pry's `show-source` can at least tell me stuff.
No. Something like "intellisense" has existed for decades. It relies on the static type system to "guess" what functions make sense in a given context. You Ctrl-Space your way to writing the code , ans get Brain cycles back to actually think about stuff.
Yes. This is the scenario in which I truly miss a good old-fashioned static type system and a big ol' intelligent IDE. Specifically, because of what you said: it frees up brain cycles for me to think about the real problems.
My highly subjective belief and experience is that Ruby and its ecosystem has enough other perks to make up for this loss. But, I definitely accept others might feel otherwise.
First, if you're writing any kind of big code, than somewhere, in your code base, someone else is writing a code where the user name is spelled `username`. Or `user`. You don't have to be "asleep at the wheel" to not remember, or not know, which is which. So you're going to type the wrong one (not necessarily on purpose), and you'll get a runtime error. Not that bad, sure, but you'll get it.
Also, at some point, you'll realize that a string is not the ideal way to represent a user name [1], and some of the functions that deal with users are going to start returning a Struct %User{first_name: ..., middle_name: ....}. Or will it be a Map %{"first_name" => ...} ? And surely you're going to track all the calls of `foo` to fix them. And all the calls of all the calls of `foo`, because, who knows ? And suddenly you're doing the mental job of a static type checker. Surely you're not "asleep at the wheel" anymore, because you're doing the work of the wheel by manipulating the gears by hand.
Bottom line: I'll gladly admit that I'm too old and stupid to do that anymore. I had typechecking in the 90s. Give it back.
[1]: https://www.kalzumeus.com/2010/06/17/falsehoods-programmers-...