I've never seen anyone complain about this, so maybe I'm alone, but the runtime error messages are absolute garbage. Especially if you get an unexpected nil that bubbles up, you'll often see cryptic erlang messages that don't really identify what went wrong. (Think type errors that don't identify the expected type nor the type passed.)
And by that same line of thought, it's frustrating as a functional language given its almost complete absence of built-in monadic types and helpful sugar to use them. Instead of `Maybe`/`Option`, for example, you pass tuples around tagged with atoms. This wouldn't be the end of the world except that...
There's no static typing. Which means that `match` blocks can't enforce completeness. This isn't a huge deal, but for a dynamically typed language, it's surprisingly cumbersome to introspect at runtime. Languages like Ruby make such things first class, such brings me to...
Elixir is nothing like Ruby. With the exception of `def`, `unless`, and `do`, there are nary a few similarities. This isn't necessarily a negative, but the whole notion that Elixir and Ruby share syntax is only barely—and completely superficially—true. In large part, this is because...
There is no method-style syntax. That's not uncommon for a functional language, but it's problematic when the standard library is hugely inconsistent. Is the function you want in the `List` module? Or the `Enum` module? Or is it part of the `kernel`? Hunting around for the right module is a pain, but not as bad as...
Inconsistent naming of functions. Sometimes they're fully spelled out; other times they're abbreviated. And if you're really unlucky, if it's in the kernel, you can expect 1970's Unix-style abbreviations that are so short to be unreadable and have no consistency in how they're formed. US state abbreviations follow more strict rules than Elixir kernel function names. At least one thing Ruby got very right were easily-guessable method names.
There's a lot of good in Elixir; don't get me wrong. But I've spent over a year in it and keep stumbling on very un-aesthetic issues. For such an otherwise wonderful developer experience, these pain points ring loudly.
Frankly, unless you need a lot of parallel things to happen behind the scenes in real-time, I just don't see much use case for Elixir. Its ability to fail and keep going (a major selling point) is great, except that I find it too easy to write code that fails, which can bubble up and create inconsistency in its state. I much prefer something that will help me avoid failure in the first place (Rust us great for that), or something that lets me code fast and loose and makes that experience really enjoyable (like Ruby).
I think I'm alone in these criticisms, however, because I never really see anyone talk about them, so take this all with a grain of salt. I have used a ton of languages in my 25 year career, and I had a lot of hope for Elixir. But, frankly, I just don't get it.
For highly parallel networked applications, it makes sense. For very small things that would otherwise need external service dependencies (Redis, sqlite, etc), it makes sense.
But if your focus is any other use case, I really struggle to justify its adoption. It's not as fast as advertised for anything non-realtime parallel. (Go, Java, Rust, et al all provide much faster alternatives.) It's not as quick to whip up for medium sized projects. (Like Rails.) And it's not as fault tolerant as something like Rust, which can help you avoid the faults in the first place.
LiveView—the latest "must have" for web development—is likewise disappointing, in case that intrigues you. Single-language back- and front-end development sounds great. But it's just back-end streamed to the front end, which is problematic for any significant latency. None of the benefits of front-end except not refreshing the page. It's a fun (and very impressive) toy, but you get almost none of the benefits of a real front-end app. (Such as UI changes while the data is loading.)
While I only have a little experience with LiveView, I have plenty experience with latency-laden server-side echoing to know that when it breaks down without the client doing its own best-guess updates, nobody will have a good time.
Maybe I'm just salty because I expected the Elixir experience to be more than it turned out to be. And I do enjoy some of the things it forces you to do, by virtue of its being a functional language. But at the end of the day, I personally find its warts to be significant and not worth dealing with outside of very specific use cases that it uniquely handles very well.
Your mileage may vary, but I would ask yourself: does my application needlots of real-time, parallel functionality? If the answer is anything short of "hell freaking yes!", then I would look elsewhere for serious development.
I appreciate all the hard work Jose and Chris (and of course all others) have put into their respective portions of the Elixir experience. But I think it was oversold. And I think the number of packages that haven't been touched (or issues responded to) in over 3 years may indicate that others struggle to find its value in many areas in which it was advertised to be a game changer.
And by that same line of thought, it's frustrating as a functional language given its almost complete absence of built-in monadic types and helpful sugar to use them. Instead of `Maybe`/`Option`, for example, you pass tuples around tagged with atoms. This wouldn't be the end of the world except that...
There's no static typing. Which means that `match` blocks can't enforce completeness. This isn't a huge deal, but for a dynamically typed language, it's surprisingly cumbersome to introspect at runtime. Languages like Ruby make such things first class, such brings me to...
Elixir is nothing like Ruby. With the exception of `def`, `unless`, and `do`, there are nary a few similarities. This isn't necessarily a negative, but the whole notion that Elixir and Ruby share syntax is only barely—and completely superficially—true. In large part, this is because...
There is no method-style syntax. That's not uncommon for a functional language, but it's problematic when the standard library is hugely inconsistent. Is the function you want in the `List` module? Or the `Enum` module? Or is it part of the `kernel`? Hunting around for the right module is a pain, but not as bad as...
Inconsistent naming of functions. Sometimes they're fully spelled out; other times they're abbreviated. And if you're really unlucky, if it's in the kernel, you can expect 1970's Unix-style abbreviations that are so short to be unreadable and have no consistency in how they're formed. US state abbreviations follow more strict rules than Elixir kernel function names. At least one thing Ruby got very right were easily-guessable method names.
There's a lot of good in Elixir; don't get me wrong. But I've spent over a year in it and keep stumbling on very un-aesthetic issues. For such an otherwise wonderful developer experience, these pain points ring loudly.
Frankly, unless you need a lot of parallel things to happen behind the scenes in real-time, I just don't see much use case for Elixir. Its ability to fail and keep going (a major selling point) is great, except that I find it too easy to write code that fails, which can bubble up and create inconsistency in its state. I much prefer something that will help me avoid failure in the first place (Rust us great for that), or something that lets me code fast and loose and makes that experience really enjoyable (like Ruby).
I think I'm alone in these criticisms, however, because I never really see anyone talk about them, so take this all with a grain of salt. I have used a ton of languages in my 25 year career, and I had a lot of hope for Elixir. But, frankly, I just don't get it.
For highly parallel networked applications, it makes sense. For very small things that would otherwise need external service dependencies (Redis, sqlite, etc), it makes sense.
But if your focus is any other use case, I really struggle to justify its adoption. It's not as fast as advertised for anything non-realtime parallel. (Go, Java, Rust, et al all provide much faster alternatives.) It's not as quick to whip up for medium sized projects. (Like Rails.) And it's not as fault tolerant as something like Rust, which can help you avoid the faults in the first place.
LiveView—the latest "must have" for web development—is likewise disappointing, in case that intrigues you. Single-language back- and front-end development sounds great. But it's just back-end streamed to the front end, which is problematic for any significant latency. None of the benefits of front-end except not refreshing the page. It's a fun (and very impressive) toy, but you get almost none of the benefits of a real front-end app. (Such as UI changes while the data is loading.)
While I only have a little experience with LiveView, I have plenty experience with latency-laden server-side echoing to know that when it breaks down without the client doing its own best-guess updates, nobody will have a good time.
Maybe I'm just salty because I expected the Elixir experience to be more than it turned out to be. And I do enjoy some of the things it forces you to do, by virtue of its being a functional language. But at the end of the day, I personally find its warts to be significant and not worth dealing with outside of very specific use cases that it uniquely handles very well.
Your mileage may vary, but I would ask yourself: does my application need lots of real-time, parallel functionality? If the answer is anything short of "hell freaking yes!", then I would look elsewhere for serious development.
I appreciate all the hard work Jose and Chris (and of course all others) have put into their respective portions of the Elixir experience. But I think it was oversold. And I think the number of packages that haven't been touched (or issues responded to) in over 3 years may indicate that others struggle to find its value in many areas in which it was advertised to be a game changer.
I want to like it.
I really don't like it.