Elixir v1.1.0 Released
github.com
github.com
a. After launching the "iex" shell, press Tab. You'll get the list of all built-in commands.
b. The help feature is also very handy for when you're wondering what an operator does. Type "h <command>" for a definition.
h !/1
c. Try the pipe operator. Your code will closely follow the transformations of your data.Instead of this:
m1 = "moo"
m2 = String.replace(m1, "m", "z")
m3 = String.upcase(m2)
Or this: String.upcase(String.replace("moo", "m", "z"))
Try this: "moo" |> String.replace("m", "z") |> String.upcase()
The result of each command will be passed as the first argument to the subsequent command.d. You get seamless interoperability with Erlang libraries.
:crypto.hash(:md5, "bob") |> Base.encode64
e. Try the Observer tool in iex to visualize various aspects of your running application, including the supervision tree, details on each running OTP process, and much more. Seriously very handy stuff. :observer.start()
f. If you're using EC2 like I am, Amazon images have a too-old version of Erlang, but it's trivial to compile things yourself: sudo yum install gcc glibc-devel make ncurses-devel openssl-devel autoconf
wget https://www2.erlang.org/download/otp_src_18.0.tar.gz
tar xvzf otp_src_18.0.tar.gz
cd otp_src_18.0
./configure && make && sudo make install
sudo ln -s /usr/local/bin/escript /usr/bin/escript
sudo ln -s /usr/local/bin/erl /usr/bin/erl "moo" |> String.replace("m", "z") |> String.upcase()
This is always what I thought OOP should be, but could never put my finger on. Effectively, you're calling a chain of "methods" of "objects", but each method lives in its own namespaced module, rather than automatically being assumed to live in the class associated with the data. No "this object implements two interfaces that both define add()" confusion; no objects extended to infinity with extra mix-ins and interfaces just so that more methods could be called on the object rather than having the object passed to utility functions; etc.And when you do use classes (Structs), there's line-local context-free crystal-clarity between code that expects a generic object expressing one of the class's interfaces (where calls are made on the interface's Protocol module) vs. code that expects that particular class (where calls are made on the class's module, which contains the implementations of the Protocol functions.)
"moo".Replace('m', 'z').ToUpper();
Or, fully qualified with "every method in its own namespaced module";
"moo".(string.Replace('m', 'z')).(string.ToUpper());
I'm not sure if elixir is doing anything fancy here that I'm not seeing, though. I still haven't had a chance to try it out.
More or less it rewrites
String.downcase("FOO\0BAR") |> String.split("\0")
to String.split(String.downcase("FOO\0BAR"), "\0")Smalltalk faq: "Q28. What is the difference between chaining and cascading?"
Personally I like chaining because, since I read going right to left, in my head I can go "x goes to y then the result of y goes to z" versus "z is the result of y which is the result of x" (reading it backwards)
> This is always what I thought OOP should be, but could never put my finger on.
I'm not sure what Simula did, but at least in Smalltalk this is how OOP have worked :-)
> So, pretty much whether everything is being applied right to left vs being applied left to right?
I'm not sure that's the best takeaway; consider:
$ gst
GNU Smalltalk ready
st> 2 * 3; * 3; * 3
6
st> 2 * 3 * 3 * 3
54
Now, if the object on the far left was some kind of
accumulator/container, the
effect of sending something like three "add the number 3" would be
similar to chaining. But even if you mulitply the number 2 by 3, three
separate time, 2 * 3 still equals 6.In fact, in order to get chaining with keyword messages, you apparently need to define it, or especially adapt eg: containers to return ^self. But as should be obvious, I'm not very familiar with Smalltalk. Some more on the subject: http://blog.3plus4.org/2007/08/30/message-chains/
I had not even heard of Elixir till the Phoenix framework hit 1.0 about a month ago, and right now I'm very seriously considering Elixir/Phoenix for my next startup and have been slowly learning/hacking in it.
I come from C/C++ background, so the syntax was different as it is more Ruby-ish, but still very easy to grok. I've been looking at golang as my next language, but I think Elixir is even more simpler that it. Of all the functional languages that I've tried to get into in the past, this has the most approachable syntax, and I can see things like pattern matching helping a lot with code maintainability.
The performance, from whatever I've seen and the limited benchmarks that are out there, it compares extremely well with JVM, Node and Go. Erlang/OTP brings fault tolerance, Phoenix/Ecto etc. have been very productive, community is awesome and helpful. Erlang tooling, such as observer, is awesome and I don't think we have anything similar in golang, though I could be wrong. Dializer helps with type checking.
The one thing missing is lack of a enterprise sponsor, and also number of potential hires which can be risky for startups, but on the other hand people interested in working in elixir could be an interesting hiring filter ;)
Delays kill startups, and that just begs for delays. You have to learn the language. All your new engineers have to learn it. You'll inevitably be (re)inventing the wheel because Elixir isn't in production at thousands of companies already.
Picking a shitty, slow language, as long as it's a popular one (JavaScript, Java, C#, PHP, Python), is going to have a much better cost/benefit profile.
The way I'm looking at it is implementing small examples in a couple of other options, such as Nodejs/Loopback and Java/Play and then comparing them. So far Elixir/Phoenix seems straightforward and productive, but still evaluating.
However, even if Elixir/Phoenix is the best thing since sliced bread, hiring and training is indeed going to be an issue so I've been trying to figure out how to solve than conundrum.
Maybe this is a reflection of my pessimism, but I feel that it is actually a reflection of the quality of the software. :)
[0] Yes, I know that Elixir is a BEAM language and -as such- has access to both Erlang and OTP, so this distinction is terribly fine. ;)
Many startups don't need top-tier engineers. They need productive, numerous engineers, especially at the beginning when hiring anyone is difficult (let alone someone good).
Really, language should never be a barrier to hiring... a good engineer will want to learn a new language, and in my opinion, the really good engineers are already erlang programmers.
The biggest barrier to hiring, in my experience building a team for an elixir project, was medieval HR practices. ("oh you can't hire him, cause he wants a plane ticket reimbursed for relocating across the country. He's being greedy." Seriously.)
Although, keep in mind that a startup is going to be a roller coaster ride for years. You'll have days when you get tired of writing financial models for investors, or when an angry email from a customer ruins your mood, or you hit a road-block with a UI that just doesn't feel right. You'll want to take a break from all that by going back to just writing code for a day or two. At that point, you will want to get pleasure out coding. I'll be very unhappy if after those kind of days, I try to find solace in coding, and I see PHP, JavaScript or Java staring back at me.
Compared to the years it takes to turn a startup successful, the time needed to learn a new language well enough is negligible. I knew just basic Ruby when I switched to Ruby + Sinatra from Java for my new startup. Now, three years later, I can't be happier I made the switch.
I think you're also over-estimating the time required to learn a new language to be good enough for most startups. I understand that there are some areas where language mastery will be tremendous benefit. In that case, I agree that switching languages may not be such a good idea. But, that's a special case, IMHO.
Because my experience is, as I related above, even though I was learning elixir (for real, I had dabbled with it before) an building a team from scratch, we delivered a product extremely fast.... because we chose elixir.
It doesn't matter how well you know java, the language is going to slow down your development dramatically... at lest compared to Elixir (and maybe go.)
Is it 2006? :)
Last year started a project with elixir, about 8 months before elixir hit 1.0. Despite starting with me and another engineer we both built a team, taught them elixir (the ones who didn't already know) and got a product to production within about 5 months[1].
Erlang is not new. It has been around for over 20 years. I don't think we needed to, but if there weren't an elixir library for what we needed, we had erlang libraries to fall back on. Our "new engineers" were often attracted to us BECAUSe we chose elixir. It took about a week for us to get new engineers productive with elixir (we hired good people, though).
You're over estimating the benefit of libraries and way underestimating the benefit of a really good language/platform.... and elixir/erlang is that.
It's a lot faster to create a given amount of functionality in Elixir, and then a lot faster to debug it and extend it.
And then, after making the choice to stick with an "established" language, companies are shackled to it forever, hiring people who already like that language and so they never leverage newer better ways of doing things.
[1] That was a year and several months ago that it went live. Five months may seem long, but this was a from-scratch ecommerce in a highly regulated industry involving a great deal of pulling customer records during the purchase process, with a parent company that didn't understand the concept of specs and kept changing it's mind on what it wanted. We were about %30 faster than a comparable other project at this company.
They seem to have done a lot of things right, and addressed pretty much every single criticism I had of Ruby.
> I'm very seriously considering Elixir/Phoenix for my next startup
It will be a risk, but I say go for it. Others (who have probably NOT had any Elixir experience!!) will tell you your startup is already enough risk, but here's the thing- Elixir could end up being the key differentiator technology for you. Who else provides NO DOWNTIME code upgrades, and that incredible request responsiveness as well as reliability? Immutable data? Extreme concurrency? The "Actor model" that everyone is enamored with these days? The awesome community? Nobody, I think.
This doesn't need to be a language feature, but this is possible on the JVM afaik (see Clojure).
Also, NO DOWNTIME in the context of services is kind of hard to qualify: I have no downtime for say, a web service, when doing a load-balancer deploy shuffle.
> incredible request responsiveness as well as reliability
"Request responsiveness" to some degree depends on language- a language is sometimes your upper-bound on performance.
Much more often, however, do I find that this is a function of application design. And yes, language design and application design heavily play into each other, but there are many, many languages that can achieve the same responsiveness/reliability concerns.
Haskell, many JVM-hosted languages are good choices.
> Immutable data
Almost every modern functional language. Many even do it (immutable data structures) better than Erlang/Elixir. Some even have interesting (state of the art) concurrency features that perform better in different situations - see Haskell STM (I wouldn't try and compare to Mnesia).
> Extreme concurrency
Haskell, Go, anything on the JVM, the CLR is catching up.
> Actor model
This is a bit of a subjective and semantic thing - many languages have green threads (though not all would necessarily fit the bill of "actor model" in out-of-the-box implementation, and not all are truly preemptive (most aren't)) - Haskell, Go are two good out-of-the-box implementations.
I know Haskell has an Erlang Actor analogue, not sure if Go does yet.
> The awesome community
I hesitate to use the word "niche language" - but most "niche languages" have great communities (albeit small ones) - possibly out of necessity.
I don't find that this scales often
(What would you call the "Java community?", where would you find it?, where are the pockets of "good?")
This is 100% subjective, but, I feel like Ruby has one of the best, largest communities. Some of that has bled into Elixir, for sure, to be fair.
---
All in all, Elixir is a great language, but I hesitate to recommend it without knowing more about GP's requirements and business.
(What if the GP needs to do very memory and CPU-intensive number crunching?)
You don't need Clojure; Hot Code Replacement was added in Java 1.4 (yes, that's 2002) and has been supported by application containers as well as IDEs since then.
This is definitely not a new idea.
That's missing the point that Erlang/OTP (and therefore also Elixir) is attractive because it's already a complete package. It's the intersection of a lot of different, neat technologies that becomes magical.
Try to accomplish the same things in Haskell or Clojure or Go and you'll find that you simply don't have the same tools available to you, and often they cannot be built as well as in Erlang because the foundation wasn't designed for it. And there's always some piece missing.
For example, you can build an approximation of supervisor trees in Go, but since goroutines cannot be killed, you're at the mercy of the runtime. (I also wonder if goroutines scale as well as Erlang's.) Similarly, no one has actually built a functional, immutable, process-oriented call-by-name-and-signature RPC mechanism for Go, so you'll have to invent your own. And so forth.
As a specific example, I was recently investigating OCaml to see if someone had implemented something similar to OTP. I found a couple of promising, nascent projects, but their activity all ended around 2009. Apparently nobody is doing it, even though the language seems damn near perfect for it. Never mind distributed processes; LWT is pretty weak even as an approximation of Go's goroutines.
> [downtime] This doesn't need to be a language feature ...
Erlang's live code replacement changes how you mentally think about versioning, I think. Instead of designing every piece of your infrastructure to transparently transition to a new version — using load balancers, multiple processes accept()ing on the same port, and so forth — you get a first-class language construct. This also opens possibilities beyond code deploys, such as temporarily injecting tracing into a running program. Also not often mentioned is how powerful it is to be able to connect to a running process and run the REPL inside it. (Ruby comes close here, but it's never been something you get for free.)
This is because Elixir is "just" a different syntax for Erlang/OTP which is used in very mission critical software in real world (it was originally created for telephone systems)
* Streams
* Actual macros
* Mutable variables (not data, of course)
Those would be kind of a pain to do in Erlang, maybe with parse transforms.
I personally prefer Erlang better. I like its syntax and immutable variables. Haven't hit a need to need macros too badly yet.
Everywhere pretty much. Learn a bit more how it works. Here is a good resource:
http://elixir-lang.org/getting-started/introduction.html
Here is an example:
iex(1)> x=1
1
iex(2)> x=2
2
x was 1, then it was 2. It mutated.To compare here is Erlang:
1> X=1.
1
2> X=2.
** exception error: no match of right hand side value 2
Just like in math, once X=1, it stays that. It doesn't get to mutate.Again, Elixir does not create mutation where in Erlang there was none. There is no mutation.
They decided to allow rebinding so that you wouldn't end up with a whole bunch of stupid temporary variables, which is exactly what you have to do in Erlang.
You are probably trying to say that Elixir and Erlang have immutable data. But that's what that's called "immutable data". Precisely because the variables can be mutated or not separately from the data.
> a whole bunch of stupid temporary variables, which is exactly what you have to do in Erlang.
Well we should tell Joe that it's stupid. Maybe he'll change his mind.
Other languages, like Ruby, do not work this way. If you reassign an instance variable, the memory that is storing that value actually does change.
Here, compare the same sequence of operations in Ruby and Elixir, first Ruby:
bash>> irb
>> a = {a: 5}
=> {:a=>5}
>> b = a
=> {:a=>5}
>> a[:a] = 10
=> 10
>> b
=> {:a=>10}
and now Elixir: bash>> iex
Erlang/OTP 18 [erts-7.1] [source] [64-bit] [smp:8:8] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.1.0) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> a = %{a: 5}
%{a: 5}
iex(2)> b = a
%{a: 5}
iex(3)> a = %{a | a: 10} # updates a mapping
%{a: 10}
iex(4)> b
%{a: 5}
Notice how b's value changed in Ruby, but not in Elixir. In both cases, the hash was updated.I think we are talking about two different things when we say "variables". When I say "variable" I mean x, y, a, b etc. That is the variable. It has a value, you can see it in the shell (repl) or when printing it. Look at what happens to variable x:
iex(1)> x=1
1
iex(2)> x=2
2
It was 1 then 2. It changed. Mutation is a synonym for "change". I think it is a pretty simple concept. Did the framework create a new memory cell, put a 2 in there and now x behind the scene dereferences that. Did it update the old cell in place. Was it on the stack? That's not the point. The point is x now has a new value. x is a variable that means variable x mutated.Compare to Erlang:
1> X=1.
1
2> X=2.
** exception error: no match of right hand side value 2
You can't mutate variable X. variable X is immutable. Again, I think that is pretty clear and simple.What you showed in your example is how data is immutable in Elixir but not in Ruby.
> The advantage of this is concurrency, etc. etc.
Actually most data, except larger binaries, are copied between processes anyway. So concurrency advantage is mostly theoretical. In the future they could be switched to reference counting for other things. But that is a hidden implementation detail anyway.
[edited]
I'm very curious what aspects of Python (especially unique to Python) made you feel this way.
Fun compared to C and C++.
For anyone wanting to jump into Elixir, the getting started guides are excellent: http://elixir-lang.org/getting-started/introduction.html
From there, José Valim wrote a How I Start article: https://howistart.org/posts/elixir/1
There's also a really helpful community on #elixir-lang irc. Someone is usually around to answer questions.
This is very true. I had just started playing with Elixir and had pre-ordered Dave Thomas' Programming Elixir and was going through the draft ebook, and I actually set that aside and worked through the Getting Started. It's normal the see such guides, but the material there is really, really good.
Why would one choose erlang/elixir over akka[0]? Akka seems to implement a lot of common patterns for you. It has actor persistance, cross-node failover, advanced mailbox and routing logic, and is basically a superset of OTP.
The JVM is generally more efficient, has better tooling (ide support), has better libraries, and so on.
The only point I can give to erlang is the pre-emptive scheduling, which is useful for consistently low latency.
The best known example for Erlang/Beam "http throughput" is WhatsApp's 3 million+ concurrent connections per host. I don't think you get anywhere close in Akka. Maybe max out at 50K per server? Is even that possible?
Also, I'm not aware of good examples that use Akka with Java. Everyone I know using Akka seems to also be using Scala (not sure if it is just some kind of self-selection). I really can't stand Scala's syntax. I tried two or three times but I find it too easy to encounter Perl like unreadable code. Just my opinion though.
Erlang (et. al. green thread models) has a method of concurrency that works well for situations you're using Erlang for. It's not the most efficient or most technically advanced mechanism for handling concurrency.
That being said-
> Without virtual machine support, doing concurrency is really just faking it
This is patently false, because it implies that: - A VM is necessary for "real" concurrency - (by deduction) Anything not utilizing an erlang-identical model is "faking it."
> will result in significant bugs later on that are essentially impossible to debug
I'm going to need to see an anecdote or citation for this.
Personally-speaking, I have a much easier time (quickly) understanding the execution of event-loop-backed cooperative multitasking than high-level, arbitrarily-preempted threads.
Also - I cannot see any reason why Quasar for the JVM would be any easier or harder to debug (from a theoretical, not tooling or practical standpoint) than Erlang actors.
The nuances differentiating the two models aren't great enough to merit bugs that you might see in one place or the other. Unbound, CPU-heavy tasks will cause problems for both systems.
Now this is still on the regular JVM, which will probably have difficulties JITting code that resides in those green-threads (but still better performance than erlang). Also, the entire application is subject to the regular hiccups: gc requires global safepoints, which are reached by making each thread wait when it reaches a local safepoint; on top of the stop-the-world gc operations themselves.
But things are improving: RedHat is developing Shenandoah, a GC that has STW pauses under 10ms. The only thing left is making concurrent the scanning of garbage roots(those reside in the registers and stacks). Their goal for version 2 is to get completely rid of pauses.
A few of his points that would directly apply to your question: 1. BEAM processes are lightweight which means smaller memory footprint and cheaper context switching between processes. 2. As others have mentioned, garbage collection. Processes don't share memory, so data passed between processes are copied. Virding says that this is a tradeoff, but worth the benefits of keeping garbage collection simple and fast. 3. Since processes are VM processes and not OS processes, BEAM can count the number of function calls each process makes. If a process is long running and starving other processes, BEAM can put that process back on the run queue to give other processes necessary time.
These are the ones I can remember from off the top of my head. I recommend giving the talk a listen.
https://www.youtube.com/watch?v=_Pwlvy3zz9M&feature=youtu.be
- BEAM has green-thread-local GC.
- As you mentioned, preemptive scheduling is implemented at the VM-level and is relatively elegant.
- Faster startup times (meh)
- Dynamic typing (subjective)
> JVM is generally more efficient
Depends on the scenario (and JVM implementation) - tracing, STW GC isn't always the best option.
> has better tooling (ide support)
Yes.
> has better libraries
Bit subjective, but there are certainly MORE JVM-compatible libraries.
---
Personally not a fan of Akka simply due to the underlying languages commonly used with it (Scala, Akka)
As a Haskell-user: if forced to choose between Scala and Elixir, I would choose Elixir.
Obviously that's not the be-all-end-all measure of a VM, but in the context of actors it's pretty damn important. Akka is essentially an actor library bolted onto a VM that really doesn't like what it tries to do. Some people make it work, but there's a lot of friction from the GC that gives rise to some really undesirable performance characteristics.
Given that it already beats the shit out of Erlang, I can only wonder what would happen if the Hotspot guys added a little bit of additional support ... :-)
1. GC and context switching internals. This becomes obvious quickly under load. While you can tune Akka in some ways and Akka will generally kick Erlang's ass in terms of performance, the response times and the number of usable concurrent entities are in favor of Erlang.
2. Libraries - what libraries are you going to use in Akka? JDBC/JPA? java.net? HTTP clients to pass REST requests around to modern integration endpoints? Most if not all are blocking and will bring Akka to it's knees when something freezes. Erlang libs are either non-blocking or blocking doesn't matter because it will handle millions of processes with little overhead.
3. Production ops - deploying and rolling back code in Erlang has tons of gotchas, but you can mostly change code and DB schemas on the fly in production, selectively or even run parts of the production load on your laptop to debug it. And you can deploy changes in small increments many times a day without affecting uptime.
4. Best part is failure recovery. In Akka, the node is a single OS process and single JVM. If you leak a file handle or some resource or lock and a thread blocks nothing will recover you until your OS process dies. Erlang is capable of killing processes everywhere, there is no internal global state. Even if you leak something like a file handle in a process, it will be cleaned up when the process terminates like a real OS process. Even if you leak something in ets/mnesia(the global storage), you can go ahead and clean it up from your erlang shell and production doesn't have to stop. If you leak something in Java and you haven't exposed specific interface to clean it, you will have to kill the JVM.
Don't choose Elixir/Erlang just for the language. There are plenty of functional languages to choose from.
Choose them for what OTP provides. I doubt there is any language framework with as mature an operational framework as what Erlang/OTP provides.
For a startup it might feel like an extreme case of premature optimization but if you can make the technical investment you might reduce technical debt down the line.
I think Elixir in particular allows you to still get an MVP out the door with all the bells and whistles of OTP waiting silently in the background if your startup ever reaches the volumes to justify it.
BTW, I just attended a FANTASTIC 2 day (FREE) workshop conducted by Norberto Ortigoza (twitter: @hiphoox) at the HackerDojo that gave an overview of Elixir/Erlang/Phoenix and OTP. Thanks Hackers/Founders, Norberto and HackderDojo for arranging the training.
The above is for erlang. It brings up the same VM so I imagine, if it doesn't exist, it would work as well for elixir if someone were to set it up. Perhaps we need an elixir shell project like scsh.
https://github.com/elixir-lang/elixir/blob/v1.1/CHANGELOG.md https://github.com/phoenixframework/phoenix/blob/master/CHAN... https://github.com/elixir-lang/ecto/blob/v1.0/CHANGELOG.md
I have to say it's incredible to see how quickly Elixir has developed and what the language is capable of. Between Elixir on the server side and Rust on the native space I feel like we're seeing a real growth of practical functional languages.
(I know Rust isn't as pure functional as many other languages but it's ML roots are still refreshing for writing native code)
It's the light at the end of the tunnel for a native language with a great type system and decent primitives.
Something as low-level as Rust can't deviate as far as, say, Haskell, from the procedural, register-machine reality in which we operate, and that's fine.
Études for Elixir http://chimera.labs.oreilly.com/books/1234000001642/index.ht...
My main question coming out of it: if you are going to go with a dynamic language, why go with Elixir over Python or Ruby (or Clojure or Racket or ...)? These have a larger mind-share and a more broadly recognized syntax.
Granted, Erlang (BEAM?) processes are appealing.
If you are using Erlang or Elixir, why?
Clojure allows some OO if you'd like. I see that as a drawback, personally, but I've drank the functional koolaid.
Whole "classes" indeed.
Especially for Ruby devs who are fed up dealing with concurrency and performance problems in Rails, Elixir is very attractive and will make you code in a different way.
If you ever try to do anything as interesting with types as you could in a dynamic language, you'd immediately start transporting interface{}s (essentially void*) all over the place and lose all static typing [0] (and context[1]).
[0] - https://github.com/eatonphil/gimpy/blob/master/net/http/http...
You should check out Dialyzer.
I'm trying to convince people at work to use Elixir but people seem to have language fatigue. The lack of a major company/product using Elixir is making me worried as well. But hey .. someone had to be first, right? :)
Anyone here who hasn't yet been burned by social proof, please raise their hands.
There are plenty of people using Erlang. That's good enough, IMO.
If there were ever a show-stopping problem with the Elixir compiler that couldn't (or wouldn't) be fixed, you could just write whatever functionality you needed in Erlang (Which decades of prior art exist for).
I would choose Elixir over Ruby or Python if my service needed to high reliability or if it touched the network in any significant way. Ruby and Python suck at concurrency and are "fragile" when serving lots of connections. Clojure or Scala (seriously, no one is building a product in Racket...) would be appealing but the JVM brings its own set of headaches and even with bolt-on large-scale concurrency support the JVM languages are not significantly better at these problems.
Broadly recognized syntax? Elixir is much easier for people to read than either Clojure or Scala and is close enough to Ruby that Elixir is drawing over a lot of developers from that group.
I use Elixir because it is fun, it scales well and has high performance for the problems I am throwing at it, and it helps me develop solid and reliable solutions.
I'm not sure what my point is - it's just not an easy sell?
Personal, subjective conclusion: Scala is substantially more complicated to use and learn than Elixir (to achieve the same ends).
Personal, subjective remark: Scala is substantially more complicated than Haskell. It's just so big.
If you know Elixir and are confident using it, you'll understand its benefits and when best to use it. I work for a dev shop where we use Elixir for client work. Elixir is performant and you end up making the most out of your server resources. That would be great for clients who end up having huge traffic. But more important than performance, I find it easier to maintain Elixir code largely because it's a functional language. Lastly, I think Elixir's Lisp-inspired macros are a great way to write reusable libraries/modules.
In essence, I'm more productive with Elixir than I am with Ruby even though I used Ruby for much longer. I find it a more pleasant experience maintaining Elixir code than Ruby code.
Try Jane Street's Core. I hear it's a better situation.
> "highly-performant"
On one core. Erlang and Elixir will blow it away when employing more cores, naturally.
Though OCaml would probably perform similarly or better (for certain CPU-bound tasks) when running N processes to N cores. You'll need to bring your own IPC mechanism - this is probably the key BEAM value add.
> syntax and alternative MO are still a big sell > web engineering > it's just not an easy sell?
You sell based on productivity, performance, and correctness:
"By using this technology, you will have less bugs, which is cheaper and more productive in the long-term."
Granted, this is a very hard thing to prove, it has anecdotally been my experience with ML-derivatives.
* Concurrency is not an after thought. The primary abstraction are actors (Erlang processes) that are isolated and communicate with message passing. Data structures are also immutable which helps greatly with concurrency and also leads to clearer code (it is really comforting to know that a value won't change under your feet).
* The Erlang VM: we are leveraging 30 years of knowledge in building and running fault-tolerant systems, thanks to the underlying process model. We could really go deep into this topic so I will just link to an article I wrote some time ago talking about Elixir and microservices: http://blog.plataformatec.com.br/2015/06/elixir-in-times-of-...
* Performance may also be a big deal depending on what you are doing. Elixir/Erlang are not good at number crunching but if you are running anything behind TCP/UDP, it will give you better throughput and a consistent latency compared to Ruby, Python, Node.JS, etc.
* We don't have compile time checking but we do provide type specifications and a way to check them: http://elixir-lang.org/docs/master/elixir/Kernel.Typespec.ht.... The integration between Elixir and Dialyzer is suboptimal today but if type checking is a big deal for you, it will certainly help.
TL;DR: Elixir is for building and running fault-tolerant, concurrent, distributed systems. It brings extensibility and great tooling to the Erlang VM. If what you are building requires 1. a TCP/UDP port and/or 2. running for a long time, you should definitely consider Elixir. An introduction to the language can be seen here: https://vimeo.com/131631884
That said, if I were looking into a BEAM language in the future - and after this thread I am inspired to try again - I would probably be more inclined to go with Erlang. For the same reason that Java is probably an easier sell than Scala.
However, I am most likely not your target audience. I am neither an existing Erlang user nor a Ruby user (nor even a Node user).
If your problem is one for which a fault tolerant, highly-scalable system with actor-model concurrency is an appropriate solution, Elixir (or Erlang) makes a good choice, and Ruby/Python/Clojure aren't particularly great choices for that. That they all happen to lack static type checking is not what is motivating the choice.
Also, Erlang/Elixir have fairly robust (for languages that are "natively" dynamic) type-checking available through dialyzer, which can be strength compared to other dynamic languages.
https://pragprog.com/book/elixir/programming-elixir
This is a very nice book that introduces functional programming in a way that's very accessible to people coming from Python or Ruby. Elixir is probably more accessible than, say, Haskell or Scala for someone coming from one of those languages.
Have not coded Elixir in anger, but from the look of it the immutability and composability and other benefits of debugging functional programs could be a big win over writing the same program in Ruby or Python.
https://github.com/josevalim/homebrew/blob/patch-30/Library/...
> brew edit elixir
Then just paste the new file in. You'll have to reset this eventually... which you can do for all your formulas using:
cd `brew --cellar` git reset --hard HEAD
Installs like a charm on El Capitan.
You'll see quite a few people commenting in this thread (including me) who have spent something like 10-15+ years working with OO languages, we've seen the ugly sides of mutability, dependency spaghetti, holding onto state too tightly, too much coupling between classes, and the like; not to mention the difficulty with concurrency in a world where anything can mutate global state (such as class definitions).
For a minor example, recently I was building a representation of a rectangular tiled game board, and after fighting with the stdlib and lists for a while, found I could just, out-of-the-box and with a bare minimum of effort, build a directed graph, with built in pathfinding and access.
What you get for free is phenomenal
- Erlang/Elixir (from now on I will just say Elixir) have parallelism out of the box. Node.js is a single threaded event loop so you only get CPU parallelism by forking.
- Elixir is also massively concurrent and has non blocking IO but instead of using callbacks/promises you just write your code sequentially and the BEAM (Elixir's VM) takes care of scheduling for you.
- In benchmarks, Elixir maintains a very consistent 99th percentile whereas Node's 99th percentile latency drastically gets worse as the active number of connections increase.
Which, minus the IPC, code/dependency sharing, has similar practical consequences as Erlang/Elixir: no shared heap.
> but instead of using callbacks/promises
At a level as high as JavaScript this doesn't matter, but, green threads are not as performant as this model would be in a lower-level language.
Edge-triggered, multi-threaded event loops + callbacks are a force to be reckoned with on the concurrency front.
> 99th percentile latency
Single-core tests? For both Erlang (BEAM) and Node.js?
I'd like to see this testing and the reasoning behind it, though if true, I suspect it's probably related to GC latency (and the high cost of JS execution contexts).
In Elixir/Erlang every Erlang process has its own heap. In the case of Node.js and forking, each forked process has its own heap. You can't fork 100,000 times but you can have 100,000+ Erlang processes all with separate heaps and all in the same process.
Elixir (because Erlang) handles the distributing of 'processes' (not operating system processes but Erlang lightweight process) across cores for you. Erlang's been doing concurrency for a long time, it's very good at it.
The style of programming is very different in that you are encouraged to use processes in Elixir, rather than the callback style that is prevalent in Node. It feels weird at first, but pretty natural after a while.
I'm not sure there's much you can do in Node that you can't do in Elixir. But there are features in Elixir (again, because Erlang) like hot-code-reloading (update your app whilst it is running), and the way it can distribute tasks across nodes that I'm not sure are that straight-forward with Node.
Even though I am the only one in the team who picked up Elixir, but soon we will have more. Elixir and its tooling is a welcoming change.
Ultimately you'll need to know Erlang (language) anyway if you want to use some external libraries that aren't in Elixir natively. IMO, Elixir as a language is not too different from Erlang, other than syntax.
If you come from a more traditional language background, such as C, C++, c#, java, scala, ruby, python, js and others, especially ruby since elixir is very ruby-ish, Elixir is more approachable and I'll suggest that you go with it.
If you already enjoy Erlang though? Don't get discouraged just because something is built on top of it- keep going! Elixir will be there regardless, and might even be easier to learn when you understand what it's built on.
I had an idea for a type of reverse proxy, so I wrote in on elixir + cowboy. Go to performance test it, and the results are nothing to write home about. Thought I was doing something wrong, but looking around I didn't find any performance test results that were all that different. What is the point of "lightweight threads" if the "heavier" solutions are way faster?
Here's TechEmpower's latest benchmark results. Keey scrolling till you get to an Erlang/Elixir based solution: https://www.techempower.com/benchmarks/#section=data-r10&hw=...