Types are self-documenting. Onboarding new devs in a large static codebase will be 10x easier than a dynamic one.
Coding is actually faster in statically typed projects - autocomplete works every single time and you never have to dig into another source file to see what objects/methods you have.
And, most modern type systems (Typescript, Swift, etc) don't have much overhead at all with their impressive type inference.
Vimal Kumaar touches on how it has helped them get employees contributing to the code a lot quicker, after they moved to PureScript https://www.youtube.com/watch?v=HLEwYghBjo8 (I think around 24+ minutes in, but I recommend the whole talk).
The claim is pretty facially silly at a glance besides, though. You literally don't know the fields and methods, to say nothing of what they actually give you, on a Ruby object without opening either the code or pulling up Pry and doing `ls`. Which I have done, often enough, to fail rather stunningly to miss doing so when in Kotlin or when using TypeScript. Checked that one? Good news--now you get to drill down into the next one, and the next one. I hope that isn't coming from another library, too, 'cause jumping from library to library in Ruby or Python is a chore. And even if not? God help you if you're using ActiveRecord, I hope you enjoy scanning your database migrations or describing tables just to learn method names.
It is a bad scene. And don't get me wrong; I like Ruby quite a lot. But I won't make excuses for it.
Personally, with the actual tooling available to modern systems, I write TypeScript much, much faster--we're talking probably twice as fast--than I do even ES6, which I otherwise quite like. And TypeScript can't even assert whether something is a whole number or not, unlike better languages. It has replaced Ruby for me on the strength of that alone.
I think exploratory, debug-based onboarding can be easier with poorly written static lang codebases that dynamic, but then again depends on what convetions are used. I don't care much about autocomplete unless I have to type ReallyLongClassNamesThatAreSupposedToBeMeaningful; besides coding is mostly about avoiding errors, not typing faster.
In the end, whatever floats your boat but dyn langs surely have their place.
If it's something like Java, C, C++, etc, then I can see your point, but if you pick any of the languages with type inference (like Elm, Haskell, PureScript, OCaml, F#, etc), then you rarely actually have to write types.
Working with the type system is a different way of working. It's more beneficial to see the compiler as a helping friend, instead of an adversary that is just there to complain.
Some interesting reads might be:
- http://elm-lang.org/blog/compilers-as-assistants
- https://matthew.brecknell.net/post/hole-driven-haskell/
- http://bitemyapp.com/posts/2017-09-23-please-stop-using-type...
Personally, I honestly hate every time I don't have a time system to rely on. I don't make any false pretenses that I have the whole program in my head 100% of the time. I don't want to have to think about things that a computer can solve for me, hence I like my compiler to do as much work as possible.
As for unit testing, a type system is never supposed to remove the need for unit testing, and if you see anyone promote a language because of this, they are probably (hopefully) over simplifying. What it does do though, is significantly cut down the need for certain types of tests, since you can model so much more logic via types (ADTs, Union types, etc), and get it checked by the compiler.
As an aside: I simply do not believe you've never run into a type error, unless you've only written projects that 100 lines of code, and even then it's quite easy to run into type errors.
I used to run into type errors when I first started programming but I've learned how to eliminate them by changing my programming style. I add a lot of constraints to how I program, and follow a system of naming conventions that make it obvious what type something is.
I take a lot of pride in my work and try my best to build maintainable systems that can be extended easily or run forever without changes. I typically write around 250K-350K lines of code per year in mission critical and highly regulated industries. If you want to learn how to write systems that have zero defects research companies that are known for quality design and apply their principles to your own work. I would suggest Netflix, and Toyota as the two companies that I would emulate.
And you find it unbelievable that someone would prefer that the compiler simply enforce these conventions?
AppUser.new
=> prints all properties of the object with nil values
AppUser.instance_methods - ActiveRecord::Base.instance_methods
=> prints all unique instance methods on that class
valuesconfig_options is extremely generic but I would expect that it is a Hash of key/value pairs. Given the fact that it has options in the name you are likely going to have to look it up regardless as you have multiple choices when using it. I'd expect some documentation if it is truly configurable, or you can transparently look at the method signature if it uses keyword args. (say for a library that handles formatting currency)
Quickly reading other people's code is a definite skill. While it can be a pain to do, it is worthwhile since the code is the only real source of truth.
Whether dynamic type errors become an issue depends a lot on how often all codepaths are run.
If what you're running is a batch processing script, it's likely to crash out as quickly as a type-checking compiler, and then static types have no direct appeal.
On the other hand, if it's a long-running server with a lot of finite state machines(maybe it's running a multiplayer game or something) it's really hard to reach type errors without an extensive manual test.
This becomes a relatively bigger issue as the codebase gets bigger, again depending on the type of code. If the main way the system expands is by handling a more diverse set of data types, dynamic types allow less code to be written, but also make it harder to verify.
In practice what I tend to see happening is that a glue layer appears that needs dynamic behavior, while the codepaths underneath that benefit more from static typing.
However, if you work with a junior team or you have to inherit a project, then I've found static typing to be extremely useful. One might argue that code review is suppose to solve for that, and while you can catch some of the problems, you won't catch all.
It's definitely helped to make refactoring faster. Specs will help to some degree, but static typing will traverse through every function to ensure the parameter you're passing is as expected.
No more is this suppose to be a nil, a blank value? You can specifically define what you expect. While some people hate optionals with Swift, I've found it to be an interesting concept.
Comparing my Python and Java experience, jumping into the middle of a codebase and correctly untangling a few particularly problematic spots or reworking and refactoring packages without introducing errors is dramatically easier with static typing.
It's feels like the difference between untangling actual wet noodles vs solving a sliding block puzzle. It's just more mechanical.
Even BEFORE running tests there is a lot of confidence that you haven't overlooked something. Hell, you can't catch typos in python without 100% code coverage. The sanity bar is just that much higher before you even get to unit tests.
I am the least efficient when I write code in JS.
On the other hand with Ruby, and meta programming, I can do stuff that would be impossible to express in the most popular type systems.