It’s not a false sense of security; it’s automation to cut out the stupid bottom 75% or so of boring-to-write, disastrous-to-screw-up test garbage that we all have better things to do with our time than duct-tape together.
(Also, Dialyzer is pretty bad by comparison to a real type checker. At best it’s spotty and inconsistent, it fails open in weird ways, and libraries rarely implement it. Elixir has an argument for “the least worst dynamically-typed language in common use” but Dialyzer ain’t it.)
I can tell you with 20 years of programming experience that static type systems don’t make me more efficient... and I’ve used them all.
And just because I can see the reply coming, I’ve worked with programmers using static type checking that have turned out horrible bug ridden code. It’s just not a cure all.
So can we please accept each other’s choices about type systems. “Can’t we all just get along”
Ultimately if it matters to you, then choose what works. But don't assume or try and tell everyone it makes one language definitely better than the other, because things aren’t that simple.
Then those meatbags realize that they have to refactor their code and the world ends.
The computer is infinitely better at crossing the t’s and dotting the i’s than you are. Or I am. Relying on conscientiousness when you have tools to measure and correct is a sucker’s bet. And I will go so far to say that with the wonderful tools available to us in 2020, dynamically typed languages put “on time” and “limited bugs” in an unnecessary tension.
You’re the type of programmer that tanks projects because of that arrogance and an inability to work with other “meatbags”. Maybe for you it’s all about code perfection, but for the rest of humanity it’s about making a product that works, solves a problem, makes the world a better place, or earns a profit.
Too bad my suckers bet has paid off with success and money. Best of luck with your attitude in life.
Guess these Github meatbags have made a suckers bet on a dynamic language. No way they could be efficient or successful maintaining or refactoring a project of that scale. (Yes that’s sarcasm for the sarcastically impaired)
Dialyzer isn't an answer to static type checking. It barely works half the time and cannot be relied on to check things exhaustively. It's so bad that even libraries created by core contributors have type spec errors in them regularly. Why? Because they don't use it, because it's not reliable.
Both `Ecto` and `StreamData` had these issues several times and I can only assume you could find many more if you were even more invested in using larger parts of the eco-system.
Also most PLs/frameworks have very bad testing ergonomics, so that doesn't help.
You can't publically admit to "hating tests" because that has very bad optics. So, being a static typing zealot is the next best thing (after all, it will protect you from some classes of errors that are covered by testing). You pay for not writing tests in a bit of boilerplate, but boilerplate doesn't feel like you're writing code twice.
But I also like writing tests to prove logic and rules, and not tests for data validation--because computers are incredibly good at nitpicky stupid shit, they can and should and must do it for me, and I have more important things to care about than "did they pass an int when I wanted a string?".
Modern statically-typed languages elide a great deal of that boilerplate you refer to, while still providing protection against foolish errors. And given that the rest of it acts as a runtime-introspective set of documentation for what you're doing, the rest of what you're describing as "boilerplate" provides other value as well. (The web framework I use, for example, uses your declared data types both as HTTP validation and to generate OpenAPI documentation for both humans and other computers. In a dynamically-typed language I'd still need to define these things as JSON Schema or the like--which is what happens under the hood here, it just actually provides for me dev-time and not just runtime benefits.)
Basically all of these things (or their rough equivalent) are easily testable in Elixir.
Your point is taken in the large (I wrote a zig NIF library that reads zig types and automatically generates the code that performs the data deserialization from erlang terms), but in the specific case you noted, if you're using type annotations to create your OpenAPI spec, you're doing it backwards. Best practice is to OpenAPI spec to generate endpoints that you code for. (I'm aware that phoenix-openapi does not do this correctly)
Also, I want to point out that I wrote a generalization, not an absolute statement about typing zealots. I think you're rare. I like types and even wrote an (unpublished) typing library for elixir (proof: https://github.com/ityonemo/typed_headers) that engaged during tests, with the intent to make it compile time checks. But almost every typing zealot I have worked with absolutely hated tests.
The rest--yeah sure, but you can write tests for those things in anything. What you must test is then only a subset of the things that yeah, you do really have to bust your ass to test in an Elixir or a Ruby or a Python, and then it really is boilerplate--just less useful boilerplate overall.
> Best practice is to OpenAPI spec to generate endpoints that you code for.
I disagree with that. Every project where I've ever done that has immediately shat down its leg when the spec of an endpoint changed because refactoring from external sources is bad even in languages where refactoring isn't a disaster from the word 'go'.
IMO, the code is the canonical source of functionality; the spec should reflect it. It's why my CI system for my current project builds new releases of libraries for major languages are pegged to the version of the OAS3 spec being emitted. If you want to go off-road and use a language I don't actively look at, you can still do that, and the semver of the spec (which remains a manual problem in either case, though you could probably get clever enough to make a good guess as to whether it should be major/minor/patch) will tell you as a consumer when you need to upgrade.
A semantically versioned spec is required whether or not you write the spec first or the application first
> But almost every typing zealot I have worked with absolutely hated tests.
Slices both ways pretty easy, tbh. Almost every dynamic-typing pusher I've worked with was an active danger to a project with more than one committer--the best and most effective developers on such projects have always been folks with the requisite fear and acknowledgement of their own fallibility and the absolute danger that comes with using dynamically-typed languages for anything you care about; the starry-eyed Ruby idealists (I had that phase too) are just going to be too clever by half and then you get to eat the resultant shit later.
Static type checking does have some advantages, it can ease some of the low level testing burden. For instance, using a tool like Dialyxir (dialyzer) is helpful in elixir to give you that extra security of static type checking.
For me it’s always ended up being that I’m more productive with dynamically typed languages and the flexibility they offer.