Hacker News new | ask | show | jobs
by skrebbel 2540 days ago
The needlessly dynamic typing.

In practice, Elixir data structures are rarely dynamic in nature. All structs have the same fields. Virtually all lists and maps and whatnot you end up writing will have the same type for all elements. Unlike in the JS ecosystem, there is no culture of having functions with, say, optional arguments in the middle, or arguments that can be either a number or a function or a Date object or stuff like that. Unlike the Ruby ecosystem, there's no runtime monkey patching, runtime attribute generation, runtime anything generation. Everything is as robustly typed as your average C# program, but there's no way to write that down.

Or, well, there is, typespecs. And typespecs are imprecise, hard to write, borderline impossible to typecheck (dialyzer errors are shit), and generally just barely worth it because they're so hard to use.

It just feels like.. such a waste. Dynamic typing is nice if it lets you iterate faster, but that's nearly never the case in practical Elixir code, because there's so little dynamism and magic abound (this is a good thing!). At the same time, not being able to see what values a parameter can be, not being able to ever make proper IDE support, for a language and ecosystem that is so static in nature, is just a missed opportunity.

I still really like Elixir, and I agree with the GP's love letter, but I wish it had a friendlier way for me to communicate data structures to the program, future me, and my colleagues. I still hold hope that someone (future me, maybe?) will bolt types onto Elixir in the same way TypeScript bolted them onto JavaScript. It should be easier than TS because of how static-y the entire Elixir ecosystem already is.

(Sidenote: the usual argument against static types in Elixir/Erlang is that static type checking across process boundaries is hard, if not impossible. Genius Haskellers tried it and failed. My answer is that not having type checked messages would solve 95% of my itch. In the end, most lines of Elixir code is single-process, just transformations and function calls like in any other language. I'll be happy to tell the compiler what type I expect a received message to be and crash at runtime if it isn't - just like I do when I get sent a JSON payload over a REST API or IPC or whatever)

1 comments

I've never used a proper statically typed language for web development but with Elixir can't you solve the 90% with pattern matching and guards?

For example (taken from the docs on guards):

    def foo(term) when is_integer(term), do: term
    def foo(term) when is_float(term), do: round(term)
If you tried to pass a string into foo at run time, no function pattern would be matched and it would blow up. The above should also give IDEs a way to potentially say "hey, when you call foo, it accepts a term and expects an int or float", and it's also very human readable to figure out what you need to provide as arguments without IDE support.

What's interesting about guards is you can also put expressions in there. Like `when foo > 3` and now suddenly you have a new type of integer that only accepts integers greater than 3, except it's not an explicit IntegerGT3 type you have defined somewhere.

In practice, how much worse is that vs a "real" statically typed language, other than putting guards on things is optional?