Elixir has nicer syntax but what other benefits does it offer and are there any drawbacks?
I don’t know of an exhaustive list of the benefits of Elixir over Erlang. Off hand, I know that it has far better handling of UTF-8 strings out of the box. It has improvements over OTP such as Agents and GenEvent, and it has metaprogramming/macros which is huge. Elixir has a better ecosystem of tools and will continue to add features that improve programmer productivity because that is a primary design goal, e.g. PR: Introduce calendar types.
There’s a decent summary on the Elixir blog in the Extensibility section.
Comparing the languages as such, the only difference is in fact the syntax, since both target the same VM.
If you consider the Standardlibrary part of the language then Elixir stands out against Erlang very strong, since Elixir does abstract away some things you always need to be aware of when using Erlang. As an example, in Elixir you can handle quite a lot of different container types the same way through the
Enum module, while in erlang you always need to be aware of the actual containertype.
Also in Elixir the setup of GenServers and such is much easier due to its metaprogramming capabilities. Also as @uranther already has mentioned, there are currently no lightweight replacements for Agents and GenEvent, but one could build them from a GenServer.
I don’t consider the ecosystem of one language better than other. Now since rebar3 (Erlangs second most* popular buildtool) is very mature, erlangists are now able to share their libraries via hex. And like alchemists are able to use erlang packages, erlangists are also able to use Elixir packages. There are some limitations in both directions, but in general it is possible. So each language benefits from the ecosystem of the other.
For me some of the biggest benefits are:
- Elixir’s syntax is inspired by one of the nicest languages around, Ruby
- Phoenix is inspired by one of the best web frameworks around, Rails
- José and other prominent members of these communities come from Ruby and so it’s very likely that we respect and appreciate similar things. From smart choices to attention to detail, to quality, to little touches here and there, to friendliness in the community.
All that is on top of the fact that Elixir runs on BEAM - making it a battle tested technology and perfect for the modern web.
Some might say Elixir is too good to be true and making use of the ‘best’ of everything that’s out there shows that José is a very smart guy
I have tried both Erlang and Elixir. IMO,
- much nice and clean syntax than Erlang.
- You don’t have take care “no variable can be override”
- String is always UTF-8 for Elixir. You won’t mix up like “String in List and UTF-8 Binary in the Erlang”
- Have Stronger Community for Web Framework like Phoenix
- Still compatible with Erlang. You can use Erlang Library without any problems.
I’ve written more in Elixir than Erlang, but I enjoy using both.
For me, the main advantages of Elixir over Erlang are the tooling and the metaprogramming.
The tooling makes it so much to get started with Elixir, and the metaprogramming gives you real power to adapt the language to your needs.
- Tooling (mix, hex, exrm, conform, etc)
- Strings as binaries instead of lists
- easy identification of variables (only thing capitalized)
Elixir in Action has a section on pretty much this exact question. In it @sasajuric explains the benefit of how much less boilerplate code there is in Elixir. On one level it’s built-in niceties like
GenServer, but Elixir goes further by giving you a rich macros system for layering on your own abstracts, like ExActor does. (This is a crude summary of the book. It goes into more details and covers other benefits.)
I had promised myself, and José, not to get into discussions like this but someone else has already thrown down the gauntlet. So:
While you may prefer the elixir syntax, because it feels more comfortable or closer to what you are used the erlang syntax syntax, however you look at it, is simpler and more consistent.
I am an old lisper from way, way, way back so I fully understand the power of macros. And their problems as well. They are probably the best tool for writing code which is totally incomprehensible by others. So there is a very good reason that they were not included in erlang. Also if you want macros as god intended then you should use LFE.
I am ambivalent about avoiding boilerplate code. While it is nice not to have to write stuff the gain gets become small when you migrate from example code to real programs. Also even if you don’t see you have to know it is there so you can understand what is going on.
Also being explicit is good. It makes it easier for other people to see what you mean and what is happening. Hiding things is not good in the long run.
Let’s face it Agents are not really an abstraction you want to go with. I know clojure has them but they are really just global variables. With all the problems that you get with global variables. And they are implemented with gen_servers.
Yes, elixir tooling is better than erlang’s but with rebar3 we are catching up. Also I would say that tooling is more important in the beginning of a project, and with short projects, but becomes less important as time goes on.
Having binary strings is actually not that much of a benefit over lists, though it might feel more comfortable to use as other languages do it that way.
I have practically no knowledge about the web server side so I will take your word for it about phoenix being a good tool.
Etc, etc, etc …
It all boils down to which choices you make, what you feel is important and how you want to work. So while some choices made by elixir are the same as for erlang, otherwise it would not be implemented on top of erlang/otp, some choices are different. These are what makes the languages/systems different. As they quite happily coexist you are free to choose what you feel is important and go with that.
These are of course all my views, and I know many will not agree with me.
I will stop now or else I will never finish,
Depending on your needs, this can make a huge difference! Just remember, on a 32 bit machine a charlist of 100 letters length does need 100 * 4 bytes for the letters themself, 100 * 4 bytes for the pointer to the next char and another 4 bytes for
 at the end of the list, so it is 804 byte for that 100 letters.
A binary string does use 3 to 6 words of 4 byte + the data itself. So using my 100 letter string from above and assuming everything is ASCII we have a memory usage up to 124 bytes. Beeing totally unlucky and having to deal with characters which are all represented by 4 bytes in UTF-8, we had 424 bytes, just a little bit more than half of what we had with char lists.
On a 64 bit machine it were even 1608 bytes for char list vs. 448 bytes as binary string.
At least, this is how I do interpret the numbers given in the erlang efficiency guide, chapter 10.
But I have to admit, I am doing
str |> to_char_list or
str |> graphemes very often, and at least with the latter I probably make everything worse in terms of memory consumption But I feel it is much easier to transform a list of characters/single character substrings than the binary blob itself…
Don’t get me wrong with this, I don’t want to favor one way over the other, but I want to make everyone sinsible about datatypes and use cases.
One of the things I have already told about memory downsides of character lists, there is also the random access problem, as well as others.
Thanks for the post Robert - it’s good to hear a variety of views on the topic and I am sure many people will find your post very interesting.
Btw, in case others haven’t twigged yet, @rvirding is Robert Virding, one of the creators of Erlang
I find the real power of using binaries for strings in pattern matching.
It’s very easy to distinguish a list of strings from a string, while with
charlists it’s rather difficult.
I admit that the syntax of Erlang is extremely simple and quite easy to
pick up (besides punctuation). There’s always the trade-off of
expressiveness vs simplicity, and I feel like which one is better is a
question of personal preference more than anything else.
I also agree with Robert, that macros are a great feature you can easily
use to shoot yourself not just in the foot, but straight in the face. And
unfortunately I see many libraries in Elixir that heavily overuse macros
for things that could be easily solved with regular functions. That happens
especially frequent with the
use syntax that is often used to simulate
inheritance (in terms of OO). It’s important to remember the first rule of
the macro club: “Don’t write macros!” (not sure where that originated).
I’m surprised nobody mentioned protocols yet. To me it’s a very important
feature especially when it comes down to encoding/decoding between formats.
I find it quite powerful that I can define how to convert something to JSON
or that I can call the JSON encode function and not care what data do I
get. It’s a perfect example of extensibility of code for changing
circumstances - one part of the system only knows it deals with something
that can be encoded to JSON, what it is exactly and how to encode it is
Another feature of Elixir that was mentioned very briefly is the
consistency of standard library. While I understand the reasons why
Erlang’s stdlib is not consistent (backwards compatibility and stuff), it’s
still a great thing that all the collections have a
put/3 function to
insert data or
delete/2 to remove and that the order of arguments is
exactly the same. Or that predicates for use in guards are called
is_something and those that can’t be used in guards are called
To sum it up: whether it’s Elixir, Erlang or LFE I think that the more
people use either one, the more we all benefit, be it by the common
libraries we all use or the increased “recognizability” of the platform. We
shouldn’t strive to isolate those communities from one another, but to
bring them closer and encourage the exchange of ideas.
Let’s see if this reply works as I hope, first time.
Oh yes, there are many issues in choosing a good data representation. My point was just that saying that binary strings are better is not really saying very much.
As you point out binary strings generally use less memory than list strings: 1-4 bytes per character for binary strings vs 2 words per character for the list strings. However list strings are often faster as there is less copying and lists are optimally implemented.
If you are working with UTF-8 encoded characters then random access doesn’t work with either representation.
In both cases on the erlang-VM you are basing them on another datatype, lists or binaries, to implement them so it can be ambiguous what your data actually is. In the erlang shell lists of integers which can be strings are printed as strings even if that is not the intent. In elixir binaries which could be UTF-8 strings are printed as strings. Often this is correct but sometimes it can confusion. Try doing [97,97,99] in the erlang shell and <<97,98,99>> in the elixir shell. There is no way around this.
Probably the best way is to mix implementations: use lists for the string parts you work on and binaries for the rest. But there is no built in support for this.
In erlang we chose lists as this was a common way of doing it in the functional world while I guess José chose binaries as this was closer to what Ruby and other languages do.
It boils down to choices. “Pest eller cholera” as the swedish saying goes.
Hehehe, another rule on macros I have heard is “Don’t use a macro when you can use a function”.
Yes, the libraries are a problem. People complain, quite rightly, that they are inconsistent but if we then say “ok, we will fix them” they complain even more. And doing things like having new versions, for example
lists2, is even worse. This I am a bit jealous that elixir could do that.
We have occasionally had these OO drives for erlang as well but they have usually gone away after a while. Although we had an experimental parametrised modules for a few versions which was very OOish.