Elixir – mit Erlangs Erben in die Zukunft

Seite 3: Syntax, Kontrollstrukturen, Maps

Inhaltsverzeichnis

Von Anfang an war das Ziel des Elixir-Erfinders José Valim ambitioniert, schließlich wollte er alles Positive von Erlang nutzen, ohne dabei auf die Vorteile anderer funktionaler Sprachen zu verzichten. Gleichzeitig sollten die bekannten Nachteile nicht mit in die Syntax einfließen. Da verwundert es wenig, dass sich Elixir syntaktisch in großen Teilen an Ruby orientiert. Eine interessante Analyse dazu ist in einem Blog-Eintrag unter dem Titel "Closures: Elixir vs. Ruby vs. JavaScript" zu finden.

Die gewisse Verwandtschaft zu Ruby ist beispielsweise darin zu sehen, dass sich auch in Elixir Threads definieren lassen. Ebenfalls an Ruby angelehnt ist die Möglichkeit zum Generieren von Code über die sogenannte Metaprogrammierung. Beide Aspekte sind so übrigens nicht nur in Ruby anzutreffen, sondern könnten ebenso Java entnommen sein. Aber nicht nur sie standen Elixir Pate: So wurde von PHP beispielsweise das Konzept übernommen, Code schreiben zu können, der – als eigener Prozess ausgeführt – eine Response zum aktuellen Prozess generiert. Anlehnungen gibt es darüber hinaus auch an NodeJS. Beispielsweise besteht die Möglichkeit, mit Nachrichten asynchron über Sockets zu arbeiten.

Obwohl die größte Schnittmenge mit Erlang existiert, lauern beim Umstieg auf Elixir dennoch einige Syntax-Stolpersteine. Das beginnt schon bei den Operatoren: Die in Erlang verfügbaren and- und or-Operatoren etwa gibt es in Elixir überhaupt nicht. Zudem haben die Entwickler andalso und orelse durch and und or ersetzt.

Unterschiede existieren auch hinsichtlich der Variablennamen. In Erlang lassen sich Variablen explizit nur einmal vergeben. In der Erlang-Shell gibt es mit f ein spezielles Kommando, mit dem sich Variablenbindungen aufheben lassen. Im Gegensatz dazu ermöglicht Elixir die mehrmalige Vergabe einer Variablen.

iex> a = 1
1
iex> a = 2
2
iex> ^a = 3

** (MatchError) no match of right hand side value: 3

Ein Blick auf die unterschiedlichen Arten der Funktionsaufrufe lohnt ebenfalls. Die Erlang-Variante einer Summenbildung:

sum()    

sieht in Elixir folgendermaßen aus:

sum

Beim Einsatz von Funktionsparametern gibt es zwischen Erlang:

sum(a,b)

und Elixir:

sum a, b

ebenfalls Differenzen. Die Syntax wirkt bei Erlang zugegebenermaßen ungewohnt.

Einen vollständigen Überblick der Syntaxunterschiede liefert die offizielle Elixir-Dokumentation.

Selbstverständlich stehen in Elixir Kontrollstrukturen zur Verfügung. Dabei handelt es sich um if, case und cound. Unterstützt werden zudem zahlreiche Expressions, unter die beispielsweise

  • logische Operatoren wie ==, !=, > und so weiter,
  • die booleschen Operatoren and, or und not
  • sowie die arithmetische Operatoren +, -, *, /

fallen.

Zusätzlich gibt es etliche Typprüfungsfunktionen wie is_atom/1, is_binary/1, is_bitstring/1, is_boolean/1, is_float/1, is_function/1 und is_integer/1:

iex> is_boolean(true) 
true
iex> is_boolean(1)
false

Aber auch Funktionen wie abs(number), binary_part(binary, start, length), bit_size(bitstring), byte_size(bitstring), div(integer, integer) und elem(tuple, n) sind in der Sprache zu finden:

iex> <<0, 1, 2, 3>> 
<<0, 1, 2, 3>>
iex> byte_size <<0, 1, 2, 3>>
4

Das if-Konstrukt ist dabei immer interessant, um eine Bedingung zu überprüfen:

if lang == :PHP 
IO.puts "Ich bin PHP-Profi"
end

Um auf unterschiedliche Bedingungen reagieren zu können, lassen sich zudem else-Blöcke nutzen:

if lang == :PHP 
IO.puts "Ich bin PHP-Profi"
else
IO.puts "Ich mag eine andere Sprache" end

Eine weitere Möglichkeit, um Bedingungen zu kontrollieren, ist das cond do:

cond do
language == :php and not is_javascript ->
IO.puts "Ich bin PHP-Experte"
language == :php and is_javascript ->
IO.puts "Ich bin PHP- und JavaScript-Experte"
language == :SASS ->
IO.puts "Ich kann nur SASS"
true ->
IO.puts "Ich kann vielleicht alles"
end

Ein interessantes Sprach-Feature sind die sogenannten Maps. Sie stellen nichts anderes als Datenstrukturen dar, bei denen Schlüssel auf Werte zeigen und auf die sich Pattern Matching anwenden lässt. Aber Achtung, hier schlägt Elixir ganz explizit einen anderen Weg als Erlang ein. Dort kommen Maps als Ersatz für Records zum Einsatz, in Elixir hingegen sind Records Tupel, die von Modulen unterstützt werden.

Erlang und Elixir lassen sich im Übrigen auch miteinander kombinieren. So könnte man beispielsweise Funktionen in Erlang schreiben und sie anschließend in Elixir laden. (Wie sinnvoll das letztlich ist, sei zunächst einmal dahingestellt.) Blake Williams hat sich dieser Option angenommen und sie in seinem Blog anhand einiger Beispiele dargestellt.