Smart assert

A programming language like Ruby loses a lot of data when you run it. It quickly loses access to the original source code. If you write a test with Ruby's basic assert , it can only tell you that the test passed or that it didn't; it can't tell you why. Projects like ruby2ruby have tried to bridge this gap but haven't had support from the core team.

Elixir works directly with your source code to do smart things. Tests rarely need more than the built-in assert , yet meaningful errors can be displayed. Take this Elixir code:

test "makes bacon" do assert Bacon.make_bacon() == "avocado" end

By reading it, we can see that it's erroneously making bacon but looking for "avocado" . We expect that it will fail. If this were a test in Ruby (or any other language), we would see an error such as expected true, got false . Not too helpful.

In Elixir, we see this:

** (ExUnit.ExpectationError) expected: "bacon" to be equal to (==): "avocado" at test/bacon_test.exs:14

Elixir knows that == is being used in the assertion, and shows you the values on either side of == when the test fails. Now that's a useful error!

Multi-block control flow

For years I've wanted to be able to write my own control flow structures, such as an each...else that runs an else block if the each is empty (Handlebars templates have this).

The only way to do that in Ruby would be to pass several lambdas to a method, which would be ugly.

In Elixir, the relationship between single line functions and multi-line blocks is well thought out.

These two are equivalent:

# Single line if(condition, do: a, else: b) # Multiple lines if condition do a else b end

In the single line version, if is a function that takes two arguments: the condition and the clauses . The clauses are do and else .

The multi-line version needs no explanation.

But the fact that these two are equivalent means you can write a macro that works just like a built-in. Because that's how the built-ins are written, too! (source)

Consistent use of do

Developers who love Ruby like the fact that they can override built-in operators and write DSLs that look like built-in Ruby syntax.

But many of Ruby's syntactical elements are off limits. You can't write Ruby code that works like a class definition, or an if , or a case...when . Why? class has an end , but no do . There's no way to write a custom method that takes a block without do .

Elixir is consistent.

Need a module? It's defmodule...do . Need an if ? It also uses do . Same with def .

defmodule MyModule do def my_function do end end

If you want to write a macro that works like the language does, you can. Because Elixir is implemented with the same tools available for you to use.

Built-in TDD

I find it extremely difficult to learn a new language if I can't write unit tests. My confidence in writing JavaScript and many other languages went way up once I started using a decent test runner.

With Elixir, it's built in. Use the mix command to generate a new app and you're ready to go with a unit test. Run mix test to run the test suite. Done.

It even has conveniences like a test function that takes a quoted descriptive message as the name of the test.

test "extracts m3u8 from index file" do m3u8s = Streamers.extract_m3u8 index_file assert Enum.first(m3u8s) == Streamers.M3U8 [program_id: 1, bandwidth: 110000, path: m3u8_sample] assert length(m3u8s) == 5 end

And it can run your tests concurrently with a single async option (docs).

Mind-blowing metaprogramming: upcase

One of the most ingenious techniques that José mentioned didn't make it into the final cut of our video.

To capitalize a word, Elixir could implement a single upcase function that keeps a list of Unicode letters in memory and figures out how to translate between them.

Instead, it generates a function definition for each letter. They look roughly like this (source):

def upcase ( "é" <> rest ) do ["É"] ++ upcase(rest) end

A few things are going on here. Elixir can match functions on the number, type, and content of its arguments. So it looks for a letter such as é . It knows the upper case version of the letter, then sends the rest of the string to the next letter's upcase function.

Pretty cool!

Conclusion

Elixir has many of the features that I look for in a programming language. Its authors have stolen useful features from other languages, it focuses on making it easier to write complex applications, and it has a healthy balance between performance and syntax.

Elixir isn't the only way to write concurrent applications, but it's definitely one I'll be experimenting with for a few months. If you want to learn what it's about, check out our fast-paced two hour video at PeepCode:

Ready to test your skills in Ruby? See how they stack up with this assessment from Smarterer. Start this Ruby test now.