loading...
Cover image for A Quick Dive in Elixir

A Quick Dive in Elixir

kyleparisi profile image Kyle Parisi ・4 min read

What is elixir?

Yet another programming language. There are some unique characteristics of elixir that I have not experienced with other languages. First, the way I approach learning a new language might be of interest. What I do is start a repo for the language or framework, in this case elixir-kiss (keep it simple stupid).

elixir-kiss

Usage

mix deps.get
# terminal 1
iex --name a@127.0.0.1 -S mix
# terminal 2
iex --name b@127.0.0.1 -S mix

# either terminal, Node.list.  example:
iex(b@127.0.0.1)1> Node.list
[:"a@127.0.0.1"]



From there I start exploring basic ideas that I'm curious about and make branches off the original test bed.

What can you do with elixir?

The main thing you'll find elixir being used for is some kind of distributed system. It's a fun idea to think of a cluster of computers as a single application. To get an application "networked" together, you can do this in a few lines. Here is one example using a library that clusters 2 nodes.

defmodule MyApp.App do
  use Application

  def start(_type, _args) do
    topologies = [
      example: [
        strategy: Cluster.Strategy.Epmd,
        config: [hosts: [:"a@127.0.0.1", :"b@127.0.0.1"]],
      ]
    ]
    children = [
      {Cluster.Supervisor, [topologies, [name: MyApp.ClusterSupervisor]]},
      # ..other children..
    ]
    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
  end
end

There are a couple ways you could cluster your applications. The above example uses a builtin strategy called Erlang Port Mapper Daemon. Things like DNS, Multicast UDP gossip, or other API based methods can be used.

What is unique about elixir?

There are a number of unique attributes of elixir. Elixir's control flow is heavily based on pattern matching. This means you define functions based on the data structure being passed in. That looks something like:

  post "/login" do
    {:ok, body, conn} = read_body(conn)
    case Poison.decode(body) do
      {:ok, %{"email" => "", "password" => ""}} ->
        send_resp(conn, 400, Poison.encode!(%{errors: %{email: "Please provide an email.", password: "Please provide a password"}}))
      {:ok, %{"email" => email, "password" => password}} ->
        send_resp(conn, 200, "")
      {:error, :invalid, 0} ->
        Logger.info("No body provided for /login")
        send_resp(conn, 400, Poison.encode!(%{errors: %{email: "Please provide an email.", password: "Please provide a password"}}))
      {:ok, %{"email" => email}} ->
        Logger.info("No password provided for /login")
        send_resp(conn, 400, Poison.encode!(%{errors: %{password: "Please provide a password"}, email: email}))
      {:ok, %{"password" => _}} ->
        Logger.info("No email provided for /login")
        send_resp(conn, 400, Poison.encode!(%{errors: %{email: "Please provide an email."}}))
    end
  end

In elixir there are no return or break statements. The last line in a function is the return statement. This one really caught me off guard. Return statements are definitely designed for procedural mentality. Not having returns really emphasizes the pattern matching functionality.

Documentation is a first class citizen. I've never seen this before.

defmodule Math do
  @moduledoc """
  Provides math-related functions.

  ## Examples

      iex> Math.sum(1, 2)
      3

  """

  @doc """
  Calculates the sum of two numbers.
  """
  def sum(a, b), do: a + b
end

If you configure your tests to use doctests, it will actually assert against the iex> statements. Very cool.

Running elixir can be pretty complex due to it's distributed nature. But elixir is using erlang under the hood which happens to come with some handy GUI tools built in. You can see some of that here.

"Let it crash". Elixir – and Erlang – encourage you to code the happy path. Runtime errors should be allowed to crash the process. 1

Lastly, elixir has a Read Eval Print Loop (REPL) runtime ability that makes it easy to test thoughts and explore the running application.

What I don't like

Even though elixir has reasonable types (tuples, maps, lists, etc.), doing type conversion I found to be confusing. If I wanted to cast something from a map into a user defined struct, it did not go smoothly.

I was not very pleased with the database driver. The most recommended interface is an abstracted library called Ecto. To use this interface you have to define repos, schemas, changesets or queries. The queries look like some kind of Domain Specific Language (DSL) and changsets is a foreign concept to me. It's surprising that connections, prepared statements, and queries is not the suggested driver.

Some library documentation, although heavily documented, doesn't seem very helpful at times.

Final thoughts

There isn't a language that is the silver bullet for all problems. Elixir is no different. It's still a young language, being originally created in only 2011, it's foundation is based on erlang which is much older. I may look back at it when I have a need for distribution or clustering.

Some interesting links:


  1. https://10consulting.com/presentations/building-cqrs-es-web-applications-in-elixir/#34 

Discussion

pic
Editor guide