37 comments

[ 2.6 ms ] story [ 67.6 ms ] thread
I had a brief stint of working with Elixir a while ago, and got side-tracked and spent that time going down the GraphQL/Relay rabbit hole instead. During that time I was ramping up to help out on the GraphQL Elixir project [1]. I don't know its current state, but it might be worth looking into vs Absinthe (which I'm pretty sure was branched off that project originally).

EDIT: Looks like the repo is pretty abandoned actually, scratch that!

[1] https://github.com/graphql-elixir/graphql

Absinthe is completely separate from that project. I think the whole community effort is around Absinthe at the moment and it's shaping into a great library. There's also a PragProg book coming out in Autumn "Craft GraphQL APIs in Elixir with Absinthe" [1].

[1]: https://pragprog.com/book/wwgraphql/craft-graphql-apis-in-el...

It's not completely separate. The maintainer of Absinthe got started working with the maintainer of GraphQL-Elixir. I'm not purporting they still work together, just that they have common roots.

Though that's cool a book is coming out! I remember when these projects were just getting started.

Picking up new languages is fun.

I have to say things like this tickle my funny bone though:

> def backlog(board_id) when is_integer(board_id) do

What happened to good old fashioned function foo (int bar) :)

Is there an equivalent to typescript for elixir?

There are typespec annotations. The syntax using guards allows you to have for example:

def backlog(board_id) when is_integer(board_id), do: something

and

def backlog(board_id) when is_list(board_id), do: some_list_thing

I've been reading about Erlang recently, and guards (the when clause) seem much more expressive than something like type annotations for function parameters. For example, TypeScript's annotations can't express something like this (which also shows Erlang's pattern matching):

  right_age(X) when X >= 16, X =< 104 ->
    true;
  right_age(_) ->
    false.
http://learnyousomeerlang.com/syntax-in-functions#guards-gua...
Can't?
That was awkwardly phrased. I was trying to say "TypeScript's annotations can't express something this Erlang example."
Unless you're telling me Elixir has static analysis that can tell me that `right_age(18) == true` then I'm not sure how that competes with types much less is so different from any other runtime conditional.
> Unless you're telling me Elixir has static analysis

Sure does: http://erlang.org/doc/apps/dialyzer/dialyzer_chapter.html

> I'm not sure how that competes with types much less is so different from any other runtime conditional.

You can write:

  f(5) ->
     "got a 5";
  f(X) when is_integer(X), X > 1000 ->
     "got an integer greater than 1000";
  f(X) ->
      "not 5 and not an integer greater than 1000".
Sure you can do it with an if statement in some languages. Except in Erlang can also have the same guards on process message receive expressions. There would have to process all messages then check the type and somehow re-insert it back into the message queue.
Looking at the dialyzer docs and how you truncated my full question, I'm still not sure if Elixir has static analysis that is aware of those guards or not.
Sorry for being confusing. I think this might be better description of static type analysis:

http://learnyousomeerlang.com/dialyzer

Erlang is a dynamic, strongly typed language. Dynamic means the compiler doesn't do static type checks. "Strongly typed" means once a variable has a type it usually doesn't get automatically coerced to other types. So adding a string "5" and an integer 1 doesn't return a string "6" or integer 6 but throws an exception.

In addition to the compiler there is also a tool called Dialyzer. It's based on the idea of Success Types (paper on it: http://www.it.uu.se/research/group/hipe/papers/succ_types.pd...).

It checks for type inconsistencies, violations, etc just like a compiler in a traditional statically typed language. But it doesn't emit optimized code based on it. So say it deduced that a variable can only be an integer between 1 and 10 it doesn't have a way to emit some optimized assembly code based on that information. Besides the types it automatically infers, additional typing constraints can be specified by the user.

So for the guard in question, if say the second clause of right_age(_) -> wasn't there and it saw calls to the function with X=105, then Dialyzer would come back with an error with something like:

   your_module:105: Clause guard cannot succeed.
Elixir uses pattern matching for its functions. You can define multiple functions with the same name, and which function is used depends on which one "matches" first, based on the arguments.

E.g

############

# no args

def my_func() do: (something) end

# an array arg, assigning the first to "head and the rest to "tail"

def my_func([ head | tail ]) do: (something) end

# two args, so you'd call this my_func/2 instead of my_func/1.

def my_func([], %{key: val}) do: (something) end

# definition with a guard clause, so it checks the value of the arg when determining whether it matches

def my_func(val) when (val > 10) do: (something) end

# wildcard matcher for any single arg passed

def my_func(_) do: (something) end

############

Pattern matching was my gateway drug for getting into Elixir, and it's just the tip of the iceberg when it comes to what makes the language great to work with. It's particularly elegant when pattern matching responses from HTTP requests, using switch statements. No need to put try catch blocks around everything, just pattern match against a tuple with :ok and a tuple with :error

An Elixir macro guru would have to verify, but you could do some funny stuff with a macro that takes a keyword list to get syntax like:

    function foo: [int: bar] do
      bar * bar
    end
But, no the Erlang type system is not what you'd normally expect. I really like this paper on success types that kind of goes over the type system: http://user.it.uu.se/~kostis/Papers/succ_types.pdf
> What happened to good old fashioned function foo (int bar) :)

It doesn't let you do things like:

"for (int bar) and 0 <= bar <= 3" while the "when" guard construct can do that. Moreover it lets you have multiple function heads as well. So you can defined multiple for (int bar) with different conditions. Or even a "foo" with a string bar.

Also something to keep in mind : so far noone has found a way to properly typed in a strong static formally proving way the erlang and elixir paradigm. Over other things, the self() construct that return the own pid of a process is so far impossible to type well.
I've been learning elixir for past 10 months and will be releasing a project to the public hopefully by the end of the month. Is anyone interested in any specific topics? I plan to write an accompanying blog post when I release.

Stack: Elixir, RethinkDB, Inferno (react alternative) + Redux (The goal when I started was to learn new things, hence the unusual stack)

This looks awesome! It's also a kind of perfect companion piece to an Elixir/Phoenix project a friend of mine, Travis, did over at Stride[1].

I also have my own social-good oriented learning-phoenix/ecto project[2], OpenPantry, which I started some months ago after I'd learned Elixir pretty well and done a little Phoenix micro-service, but still hadn't done anything full stack or involving Ecto or Channels... We're actively looking for help building out the feature set and it's for a great cause if anyone's interested, helping those with food-insecurity to get food more easily and with more choice than many pantry programs are currently able to provide!

[1]https://github.com/stride-nyc/remote_retro [2]https://github.com/MasbiaSoupKitchenNetwork/open_pantry

Very cool writeup.

Also thanks for the reminder of how awesome my life is now that I'm out from under capital A Agile.

Elixir was my Koolaid when it comes to functional programming. After getting the hang of pattern matching, I was hooked. Everything I'd do on Ruby/Rails, I just do on Elixir/Phoenix instead.
Clojure was my FP Koolaid, but Erlang (which I learned before Elixir) really blew my mind with it's pattern matching heavy syntax. I'm happy Elixir kept it as part it's core design patterns. So agreed it's a great abstraction that every modern language should be using.

That plus extensive use of list comprehensions when working with arrays.

I think what I learned the most about my past year of working heavily in Elixir is this.. Don't learn elixir.. learn Erlang/OTP if you really want to harness the power of Elixir. Elixir is nothing but a series of macros which give erlang some convenience and better syntax.

If you learn to harness the power of Erlang, while writing it in Elixir, then you will see the beauty of it. Get away from Phoenix as fast as possible. Seriously it will do you wonders. It's so unnecessary and cumbersome.

OTP, OTP, OTP.. can't say it enough.

How does Phoenix detract from from the elixir/erlang experience? I was under the impression that it was just a web framework? I'm pretty naive on the subject—I've just never seen something like this brought up before.
Well in my situation Phoenix is really overkill. I don't build monolithic apps anymore. To me Phoenix felt lake taking Ruby and slapping it on Elixir. It didn't really feel like, "The Elixir Way." So I set out and learned Plug(which is mostly what Phoenix is).

I build all my front ends as stand alone ReactJS apps, so I found it very strange to need Phoenix at all. I started learning to work with OTP & Plug and realized that I can build a json-api spec API in complete Elixir without any phoenix requirements and if I need to add sockets it's very very trivial to do so.

The amount of code needed to make this all work in pure elixir is minimal.

Essentially I just didn't need it for the way I build applications these days.

That makes sense. I was under the impression that you were saying something along the lines "Phoenix breaks erlang," but the complaint that Phoenix is too bulky is pretty common.
I learned Phoenix and OTP at basically the same time. I knew I'd need to build out a worker queueing system as part of a web app, so I started reading an OTP book while I was building the initial structure of the Phoenix app. By the time I needed to do more interesting things than just a crud app, I could work with GenServers and Supervision trees.

The moment that the lightbulb went on for me was when I ran `iex -S mix` in my Phoenix project and fired up erlang's observer to see its processes. I realized that phoenix is just a supervision tree made up of different microservices, much more complicated than the toy projects I'd built, but still relied on the same OTP tools and patterns. And once you understand that, it becomes trivial to use OTP to expand the functionality that Phoenix gives you out of the box.

I think what you're trying to say (and I agree if you are) is that Phoenix and Elixir are great, but you are missing out on what makes Elixir so powerful (Erlang/OTP and BEAM) if you stop there.

Yep, that's exactly it. I'm just not very eloquent ;)
I do Erlang full time. But seeing how much traction Elixir has, I say learn whatever looks more interesting. If you're developing for the web and Phoenix looks good, start with Elixir.

At the end of the day, they are both built on the same foundational concepts. You might find that you need to look up Erlang docs or find an Erlang SO answer so might as well learn the basic Erlang syntax as well. Then you have access to a larger community. Listen to Erlang Factory or Joe Armstrong's videos and so on.

Thanks for the write-up. Have you thought about using gigalixir.com instead of Heroku?
Sounds cool. Should probably add disclaimer that you're the founder.
Oh my bad, I usually do that. I can't seem to edit my comment though..
I picked up Elixir and LFE (Lisp Flavoured Erlang) at the same time. I prefer Lisps, and so I stuck with LFE, so my knowledge of the current state and capabilities of Elixir is lacking. Robert Virding who co-created Erlang, created LFE. He responded to Jose Valim in 2013 in a LFE vs Elixir thread [1].

I was accused of spreading misinformation when I made the same point recently on HN in another Elixir thread [2].

So my question is: Does Robert Virding's point still hold about Elixir's macros only able to use its predefined syntax, and not create new syntax like a Lisp can. I like Elixir, I just prefer Lisp's syntax. However, if Elixir is making these type of improvements I may want to revisit it, and to ensure I am not repeating old, incorrect information.

Robert Virding uses this example (look at the thread for context):

>> (defmacro kl >> ((list* k v rest) `(cons (tuple ',k ,v) (kl ,@rest))) >> (() ()))

>> which I can use

>> (kl a (+ 2 7) b 6) ==> (#(a 9) #(b 6))

Can Elixir do this or not?

Thanks!

  [1]  https://groups.google.com/forum/#!topic/lisp-flavoured-erlang/ensAkzcEDQQ
  [2]  https://news.ycombinator.com/item?id=14390916
Yes, sorta.

The point I think he was trying to make was that Lisp's syntax is less restrictive, but that seemed to get confused by:

- mentioning the some people say it has no syntax (which it definitely does have)

- saying macros can create new syntax (which they can't in Lisp)

Elixir macros are approximately the same as Lisp macros (apart from not being able to take a variable number of arguments).

This is a straight port of that macro into Elixir:

  defp kl_i([k, v | t]) do
    quote do
      [
        {unquote(Macro.escape(k)), unquote v}
        | unquote kl_i t
      ]
    end
  end
  defp kl_i([]), do: quote do: []
  defmacro kl(l), do: kl_i l
  
  # usage
  IO.inspect kl [a, 2 + 7, b, 6]
  # => [{{:a, [line: 16], nil}, 9}, {{:b, [line: 16], nil}, 6}]
Note: Elixir's syntax does get in the way a bit here, the `a` and `b` are converted into nullary calls, you could use a different escaping function to fix this

  defp escape_key({v1, v2}), do: {escape_key(v1), escape_key(v2)}
  defp escape_key({:{}, pos, els}) when is_list(pos), do: {:{}, pos, Enum.map(els, &escape_key/1)}
  defp escape_key(els) when is_list(els), do: Enum.map(els, &escape_key/1)
  defp escape_key({sym, pos, nil}) when is_list(pos), do: Macro.escape sym
I sort of get it. But this part he writes in the discussion seems to hold, no?

"What I mean here is that elixir has a predefined syntax. It has a number of predefined syntactic constructs, operators and function calls. And while I can with macros change the meaning of the constructs I cannot add new constructs or operators as the handling of macros is done after parsing. So if I want to add something completely new it ends up syntactically being a function call. Now elixir has many ways of disguising function calls at the end of the day they are syntactically still function calls. For example parentheses around arguments are optional, there is special syntax for property lists where the keys are all atoms, special syntax for using these property lists as function arguments, special handling of do ... end when it is a function argument, etc. Elixir's uniform abstract syntax makes it easier to work with these but I am still limited by only having the existing syntax."