Side note, I wish variable rebinding were off by default but allowed on names with a sigil (or a ! ).
I feel like anyone who has written a Yacc-based parser for programming-language syntax will appreciate Elixir's grammar even more for these "quirks." Elixir's syntax is as beautiful as it can be while also being explicitly unambiguous. Which means that the language syntax is very easy to change or extend—unlike other PLs I could name, where the set of parsing rules resembles a late-game Jenga tower.
Or, to put that another way: Elixir isn't just a joy to use; it's a joy to be a core maintainer of. (How often have you ever heard anyone consider that part of a programming language's UX?)
Oh, and this simple, explicit set of parse rules also results in a highly-predictable and regular AST, which means you can write an macro-based DSL library in Elixir—one that will actually works with any arbitrary Elixir code hanging out inside your macro body—in not-much code, and without worry that a minor language change in the future will break your lib.
Any time lisp macros come up?
However, this is really minor in the grand scheme of things, it really is one of the most beautiful pls otherwise
It’s hard to sell anything that’s not in the TIOBE top 10.
To answer your comment more directly though, for many systems the benefits of excellent concurrency, monitorability, and fault tolerance can outweigh those of a strong type system or raw performance. It really depends what you’re doing, and how your team likes to work. No such thing as a silver bullet and all that.
Eg JavaScript lets you trivially memoize asynchronous requests, by caching Promise objects instead of responses. In Elixir you'll end up with enormous case expressions like this one: https://github.com/melpon/memoize/blob/master/lib/memoize/ca...
A task is a process that calculates something and eventually returns a result, which you can get synchroneously with `Task.await/1`. There's also an equivalend for Promise.all, which is just `Enum.map(tasks, &Task.await/1)`.
You can store an Elixir task but you can only await it once. You can `.then` a JavaScript promise as often as you want which makes a promise an excellent primitive for caching things that take time (eg network requests) without triggering the same request twice.
Every time someone says "just make a process and a supervisor, put it elegantly in the supervisor tree, go think through the failure modes, ponder a bit about these 3 or 4 edge cases and potential race conditions, and you're done! hooray!" I get a bit grumpy.
Elixir is awesome, but there's a simplicity to a single-threaded execution model that takes away a lot of the things that make concurrency hard.
All I'm saying is that there are things that Elixir isn't the best at. Is that so weird? I feel like everybody responding to me has this strong emotional need to defend Elixir. Why? it's just a tool. Like any tool it has pros and cons.
https://github.com/fazibear/export and https://github.com/hansihe/rustler