Erlang is a unique platform in its capabilities, and despite this, the language is still exotic. There are several reasons. For example, tight arithmetic, unusual syntax, functionality. These are not flaws. These are just things that most programmers are unable or unwilling to work with.
A few days ago, Jose Valim published in his
repository a draft language built on top of Erlang. This language has a simple object model and a Ruby-like syntax. Under the cut of extracts from the documentation and video, showing a simple example.
disclaimer:% username%, before drawing conclusions about what elixir can do, and what elixir doesn’t, please go through at least readme .')
Elixir is a programming language that runs on top of Erlang. Like Erlang, it is a functional language with rigorous computation, one-time assignment and dynamic typing, designed to support distributed, fault-tolerant, non-stop code-hot-swap applications. Elixir allows you to call Erlang modules without the need to convert data types, so there is no performance loss when calling Erlang code.
The main difference between Elixir and Erlang is syntax and object orientation. Elixir provides a very simple object model and syntax, mostly based on Ruby.
Currently, the main task is to develop a standard library. Most of the existing standard library is written in Elixir itself, and you do not need to know Erlang to contribute to its development. It will be enough to get acquainted with the principles of OTP.
To get started, first you need to clone the repository to your computer, compile and test it:
$ git clone https://github.com/josevalim/elixir.git $ cd elixir $ make test $ bin/elixir -v Elixir 0.1.0
Comments in Elixir, as in Erlang, are denoted by “%”:
% This is a commented line
Next, “% =>” shows the value of the expression:
1 + 1
Elixir supports integers and fractional numbers:
2 + 15 % => 17 - 13 * 10 % => -130 1986 - 1985 % => 1 5 / 2 % => 2.5 4 / 2 % => 2.0
As in Ruby, any construct is an object. We can call methods on numbers:
-1.abs % => 1 5.div(2) % => 2 %surprise ! 1.+(2) % => 3
Atoms in Elixir are called Symbols (as in Ruby). But the syntixis is borrowed from Lisp (Jose explained this on Twitter with what he wants ":" to use in dictionaries):
'atom 'Atom 'atom_without_spaces '"Atom with Spaces"
Lists are the most useful structure in Elixir (as in any other functional language), I can contain anything and have a set of methods:
% Some list with elements ['atom, 1, 2, 3, { 'some, 'tuple }] % An empty list [] [1, 2, 3].length % => 3 ['a, 'b, 'c][1] % => 'b [1, 2, 3] + [4, 5, 6] % => [1,2,3,4,5,6]
Lists in Erlang and Elixir are implemented as linked lists, so pre-adding items is much faster than the following:
list = [2,3,4] % Don't do this: [1] + [2,3,4] % => [1,2,3,4] [0,1] + [2,3,4] % => [0,1,2,3,4] % Do this instead: [1|list] % => [1,2,3,4] [0,1|list] % => [0,1,2,3,4]
You get the real power of lists when you use them with functions.
[1, 2, 3].map do (x) x * 2 end % => [2, 4, 6] [1, 2, 3].foldl 0, do (x, acc) acc + x end % => 6
Strings in Erlang are represented by a list of characters:
"hello" == [104, 101, 108, 108, 111]
This is expensive because each character takes 8 bytes of memory (not a bit!). Elixir implements strings in the form of utf8 binary strings:
% The famous "hello world" string "hello world" % A string converted to its underlying binary: "hello".to_bin % => <<[104, 101, 108, 108, 111]>> % A string converted to a char list: "hello".to_char_list % => [104, 101, 108, 108, 111] % Strings are UTF-8 "Arrow ⇧ up".length % => 10
This is a significant change. Strings are the only objects that need conversion:
% Converting a string_from_erlang to Elixir's String String.new string_from_erlang % Where string_from_erlang is either a binary: <<[104, 101, 108, 108, 111]>> % Or a char_list: [104, 101, 108, 108, 111] % Converting a string_from_elixir to Erlang "string_from_elixir".to_bin "string_from_elixir".to_char_list
Finally, the lines support interpolation:
"string #{'with} interpolation" % => "string with interpolation" "1 + 1 = #{1 + 1}" % => "1 + 1 = 2"
Functions are an important part of Elixir, like any other functional language. Functions can be created using "do" or "->":
my_function = do 1 + 2 end my_function() % => 3 another_function = -> 1 * 2 end another_function() % => 2
Like Erlang, Elixir supports Pattern matching and unit assignment.
% Let's bound the variable x to 'foo x = 'foo % Now let's match a tuple with other tuple. % Since x is already bound, we are comparing x with 'baz and it will fail: { x, y } = { 'baz, 'bar } % In this case, we compare 'x with 'foo and it matches. % Since y is unbound, we assign 'bar to it: { x, y } = { 'foo, 'bar } x % => 'foo y % => 'bar [h|t] = [1,2,3] h % => 1 t % => [2,3] % Raises an error because h was already assigned to 1 and 1 does not match 2 [h|t1] = [2,3,4]
As in Eralng, pattern matching is used in function signatures:
module Math def fibonacci(0) 0 end def fibonacci(1) 1 end def fibonacci(n) fibonacci(n - 1) + fibonacci(n - 2) end end Math.fibonacci(0) % => 0 Math.fibonacci(1) % => 1 Math.fibonacci(3) % => 2 Math.fibonacci(10) % => 55
Calling Erlang methods is quite trivial:
% Accessing the is_atom BIF from Erlang. % This is the same as `is_atom(foo)` in Erlang. Erlang.is_atom('foo) % => true % Accessing the function delete from module lists. % This is the same as `lists:member(1, [1,2,3])` in Erlang. Erlang.lists.member(1, [1,2,3]) % => true
The Elixir object model has some aspects:
- Dynamic choice of implementation - when the method is called, the object itself chooses which code to execute
- Mixins - objects do not contain methods. All methods are packed into modules that are mixed into objects.
- Encapsulation - methods can be public, protected or private.
- Open recursion - objects have a special variable self, which allows you to call other methods of the object without affecting the chain of calls.
- Reflection - Elixir is able to view and modify the structure of an object at runtime.
object Person def constructor(name, age) end def name @name end def age @age end def name(value) self.set_ivar('name, value) end end person = Person.name('john, 24) another_person = person.name('john_doe) person.name % => 'john person.age % => 24 another_person.name % => 'johh_doe another_person.age % => 24
This is a description of a small part of Elixir features The repository published excellent review
documentation . The video below illustrates a small example of how the language works: