* Pattern matching in Elixir is superior to Scala's in every way possible (You can pattern match on function parameters!!)
* Async code is a breeze with Task.async()/Task.await() instead of mapping on Future's everywhere and making sure you have the proper implicit globals imported
* Actor pattern is built into the language and it's a breeze to work with. No need to rely on Akka to replicate it
* JSON is a joy to work with
* Documentation is fantastic in the core language and many libraries
* No more JVM!
* Building a release is much easier than dealing with SBT
If you have a functional background, I would recommend reading Elixir in Action as a starting point. It already assumes you have an FP background and takes you into more of the core features of the language. I really enjoyed it and the content is superb.
You're just trading one VM for another, though. How does having a Beam VM environment differ from a JVM environment?
BEAM has many great advantages such as fault tolerance and multi-node distribution built in. This allows concurrency to be a first-class citizen for applications running on the BEAM. I'm not saying that concurrency can't be done on the JVM, but that I've found it to be much simpler using BEAM. On the other hand, the JVM excels at computational work compared to the BEAM. Both VMs have their place and can be better at different types of problems comparatively.
How? Can you provide a link about this?
@compile [:native, {:hipe, [:verbose, :o3]}]
:-o
But it doesn't produce a native binary, does it?
Is using HiPE a standard practice in the Erlang/Elixir community? What is the quantitative performance gain?
I just discovered about HiPE as well, and I just gave it a try with a simple fibonacci module. Running fibonacci(40) went from 3.9s BEAM to 0.7s HiPE.
I know it's a silly test, but it's pretty sweet to witness such a massive difference out of the box. :)
I won't say testing HiPE with fibonacci is silly because this is exactly the kind of numerical computation where we expect HiPE to be useful: it looks like it is :-)
What sorts of scales are you talking about when you refer to "computational work"?
Also, was/were the comparison(s) you're referring to being done using native code?
On the other hand, the Java/JVM ecosystem is much larger, so there's a serious trade-off there.
You can learn more about BEAM here: https://www.youtube.com/watch?v=_Pwlvy3zz9M&feature=youtu.be http://www.erlang-factory.com/upload/presentations/708/Hitch...
For example, BEAM puts the process call stack on the heap, so you don't need to tune them separately. You won't hit a stack overflow, you'll just run out of memory.
Many, many characteristics like that exist. I prefer a working slow system over a broken system, but I fully understand the preference for loud failures.
* Immutable data. This ties into "functional" section below but it is worth mentioning separately. The benefit here is it is a better fit for concurrency and correctness.
* Lightweight processes. Can have millions of them. But they don't share the heap so act like OS processes in that respect. That means 2 things:
1) It changes the way you think and solve concurrent problems. It reduces impedance between real life problems and how they are solved. Spawning a new process for each long lived connection is obvious and easy.
2) Fault tolerance. Having one request not crash the whole server is a really a massive improvement. In C++ or Java you don't know if something got messed up because of a crash. Maybe some shared data structure or lock got left in an inconsistent state. There is just no guarantee.
* Hot code loading. This is not just a gimmick but it works. Most places don't use it to update regularly and I don't either. But used it a few times in production to add extra logging, fix a customer specific issue without shutting down the cluster before the fix was released. All the while there were 100k/sec requests pounding it. That is plain old money in the pocket. No downtime, no headaches.
* Tracing. BEAM has very good tracing support. When debugging I am quite fond of just logging into a node and using tracing instead of print or log statements.
* Functional. This is more about Erlang the language, and it kind of goes with immutable data. But because of that it means state is more visible and explicit. Looking at a piece of code on a page, I get more context of what is happening because State is passed, updated and returned. As opposed to being some "this" reference which at that point in the code, I don't have any idea how it was modified or what it has in it.
* Garbage collection. BEAM has excellent garbage collection. It is pause-less, in the sense that GC of one process won't block the world. Java has lots of tweaks for that but it is not a default state of affairs.
Welp, this is just a quick list off the top of my head.
At the end of the day, one can probably go through the above list and say I can do all that in Assembly or C. Which is true. BEAM is written in C in large part. To get fault tolerance, can just spawn OS processes in any language. To get immutability, can just go to Github and find an immutable collections library for Python or Java. Java can also do some code loading. But the difference is, it all comes in a single package ready to use. That is huge and I see it as a great benefit.
You can use https://github.com/scala/async for async/await in Scala. It's super easy.
Also, you can pattern match function parameters in Scal using PartialFunction `case` syntax.
which can serve as documentation and are used by a tool called Dialyzer during the build process to find errors based on the type specs.
I have not used this particular tooling first hand, but my sense is that it is well-integrated and works well. Someone else will probably comment with first-hand experience.
The Elixir compiler seems to catch a lot of errors, for what it's worth. If you attempt to call a function that doesn't exist or with the wrong arity, you're going to get an error (even w/o any type specs). The number of compiler errors one has in a statically typed language that are really just about types may not be that many.
w/r/t static vs dynamic, in general, these are the things I'd consider (if you haven't already): you're domain (are you building a rocket or a consumer-facing web app), you're appetite for testing, size of project, size of team, specifics of the tooling w/r/t refactoring (elixir's compiler is pretty good for supporting a big rename, for example; ruby, without a compiler and with so many language features, not so much), how the language makes you feel when you use it (dynamic wins here in general for me; I don't like to be in trouble or interrupted when I'm thinking), the collections library (this is big for me -- I could never go back to a weak collections library -- Go, I'm looking at you), Etc. YMMV, qualifier, qualifier. In general, the specifics really matter -- both of what you're doing and the specific tooling and how they interact.
Elixir seems to strike a very nice balance of all these things with a just right, small, extremely powerful feature set on a rock solid VM with astounding concurrency and distributed computing facilities, if you need them. By all means, I would try it.
Personally, when I used Dialyzer in Erlang, I was underwhelmed by the amount of errors Dialyzer caught (type checking concurrent code is hard, who knew?) — however, it is certainly better than nothing. Plus, the type specifications you have to annotate your functions with help with documentation :)
Reading about Elixir is cool sometimes, but then I look at Dotty, and I feel confident that I made the correct choice.
I've also been keeping an eye on Crystal (statically typed Ruby-esque language, LLVM), but they aren't making great PLT choices so far. Maybe they'll get it together later. Scala-Native will blow it out of the water most likely anyways.
Sort of the opposite of losing statically typed programming, but I've really enjoyed the journey and it's improved my work a lot more than I thought it would. I know Ruby pretty well and I used to feel really dumb all the time when things would break, and it took some time for me to realize that it was a language problem. Looking back and reading some of the Ruby that I ported, it was impossible to reason about, and very difficult to make guarantees for. Nothing was solid at all, and runtime errors could hypotehtically stop the show at any time. With Scala there's a much sharper baseline of what will definitely work or not work.
Types make a LOT of things so much easier, in exchange for making a few things SLIGHTLY more tedious. After doing it, I'd make that trade ten more times if I had to.
But even with a JIT compiler, LLVM doesn't provide the kind of runtime services (e.g., memory and resource management) that we would typically associate with a VM runtime like the JVM's. Like their Web site says, "Despite its name, LLVM has little to do with traditional virtual machines, though it does provide helpful libraries that can be used to build them."
Where does this impression come from? The BEAM VM is maintained by Ericsson, we get new "major" releases every year. In the last years we got the maps data type, the new scalable timer API, better tracing facilities, dirty schedulers, and so on. Lately, at ElixirConf Berlin, we heard about the current efforts on scaling the Erlang Distribution to thousands of nodes out of the box (it is already possibly today, just not by default).
They are also plenty of research projects, mostly in Europe, about improving the VM, development experience and scalability in different ways, such as http://release-project.eu/, http://www.prowessproject.eu/ and http://paraphrase-ict.eu/. That's not including the usual suspects like Chalmers and Uppsala in Sweden, which have been exploring different aspects, specially in the testing area with property-based testing, concolic testing, systematic concurrent testing, etc.
Companies like Adapteva (behind Parallella), Basho, Erlang Solutions, Plataformatec, and many more are investing in the ecosystem too. If there is one thing I am not worried about is the VM and the runtime bright future.
In my opinion, the simple fact we have a runtime with preemptive light-weight processes from the ground-up (instead of tackled on top as a library/framework) with per process garbage collection and inter-node communication taken care of is enough to hold the VM for the next handful of years, even if all development ceased today.
That means being chained to JVM. That is a big downside for me.
So yeah, no.
Is Scala Native used widely? They just finished implementing java.lang.String 20 days ago or so. At least Erlang on Xen has been serving web pages for a few years now: http://erlangonxen.org
But most usage of Scala is on JVM still, wouldn't you agree? We are not talking CPython/Jython/PyPy/Numba... I don't know, the claim that Scala is widely implemented on other platforms while Elixir is tied to BEAM doesn't quite go far for me.
Scala Native is not very far along compared to Scala.js, but it is actively being improved, and is considered an official extension. Additionally, Dotty will bring huge improvements for JVM scala.
I am not super happy with JVM most days, but I'd far and away prefer to be chained to JVM than BEAM. I mean, it's not even a question at this point, considering the billions of dollars spent developing JVM and the work of the brightest minds of several generations. Joe is a cool guy and all, but Erlang is objectively a niche platform compared to JVM.