Seven More Languages in Seven Weeks: Elixir

So frustrating. I had high hopes going in that Elixir might be my next server-side language of choice. It’s built on the Erlang VM, after all, so concurrency should be a breeze. Ditto distributed applications and fault-tolerance. All supposedly wrapped in a more digestible syntax than Erlang provides.

Boy, was I misled.

The syntax seems to be heavily Ruby-influenced, in a bad way. There’s magic methods, black box behavior, and OOP-style features built in everywhere.

The examples in this chapter go deeply into this Ruby-flavored world, and skip entirely over what I thought were the benefits to the language. If Elixir makes writing concurrent, distributed applications easier, I have no idea, because this book doesn’t bother working examples that highlight it.

Instead, the impression I get is that this is a way to write Ruby in Erlang, an attempt to push OOP concepts into the functional programming world, resulting in a hideous language that I wouldn’t touch with a ten-foot-pole.

I miss Elm.

Day One

  • biggest influences: lisp, erlang, ruby
  • need to install erlang *and* elixir
  • both available via brew
  • syntax changing quickly, it’s a young language
  • if do:
  • IO.puts for println
  • expressions in the repl always have a return value, even if it’s just :ok
  • looks like it has symbols, too (but they’re called atoms)
  • tuples: collections of fixed size
  • can use pattern matching to destructure tuples via assignment operator
  • doesn’t allow mutable state, but can look like it, because compiler will rename vars and shuffle things around for you if you assign something to price (say) multiple times
  • weird: “pipes” |> for threading macros
  • dots and parens only needed for anonymous functions (which can still be assigned to a variable)
  • prints out a warning if you redefine a module, but lets you do it
  • pattern matching for multiple functions definition in a single module (will run the version of the function that matches the inputs)
  • can define one module’s functions in terms of another’s
  • can use when conditions in function def as guards to regulate under what inputs the function will get run
  • scripting via .exs files, can run with iex
  • put_in returns an updated copy of the map, it doesn’t update the map in place
  • elixir’s lists are linked lists, not arrays!
  • char lists are not strings: dear god
  • so: is_list “string” -> false, but is_list ‘string’ -> true (!)
  • wat
  • pipe to append to the head
  • when destructuring a list, the number of items on each side have to match (unless you use the magic pipe)
  • can use _ for matching arbitrary item
  • Enum for processing lists (running arbitrary functions on them in different ways, like mapping and reducing, filtering, etc)
  • for comprehensions: a lot like python’s list comprehensions; takes a generator (basically ways to pull values from a list), an optional filter (filter which values from the list get used), and a function to run on the pulled values
  • elixir source is on github

Day Two

  • mix is built in to elixir, installing the language installs the build tool (nice)
  • basic project template includes a gitignore, a readme, and test files
  • source files go in lib, not src
  • struct: map with fixed set of fields, that you can add behavior to via functions…sounds like an object to me :/
  • iex -S mix to start iex with modules from your project
  • will throw compiler errors for unknown keys, which is nice, i guess?
  • since built on the erlang vm, but not erlang, we can use macros, which get expanded at compile time (presumably, to erlang code)
  • should is…well…kind of a silly macro
  • __using__ just to avoid a fully-qualified call seems…gross…and too implicit
  • and we’ve got to define new macros to override compile-time behavior? i…i can’t watch
  • module attributes -> compile-time variables -> object attributes by another name?
  • use, __using__, @before_compile -> magic, magic everywhere, so gross
  • state machine’s “beautiful syntax” seems more like obscure indirection to me
  • can elixir make me hate macros?
  • whole thing seems like…a bad example. as if the person writing it is trying to duplicate OOP-style inheritance inside a functional language.
  • elixir-pipes example from the endnotes (github project) is much better at showing the motivation and usage of real macros

Day Three

  • creator’s main language was Ruby…and it shows :/
  • spawn returns the process id of the underlying erlang process
  • pattern matching applies to what to do with the messages a process receives via its inbox
  • can write the code handling the inbox messages *after* the messages are sent (!)
  • task -> like future in clojure, can send work off to be done in another process, then later wait for the return value
  • use of Erlang’s OTP built into Elixir’s library
  • construct the thing with start_link, but send it messages via GenServer…more indirection
  • hmm…claims it’s a “fully distributed server”, but all i see are functions getting called that return values, no client-server relationship here?
  • final example: cast works fine, but call is broken (says process not alive; same message regardless of what command sent in (:rent, :return, etc)
  • oddly enough, it works *until* we make the changes to have the supervisor run everything for us behind the scenes (“like magic!”)
  • endnotes say we learned about protocols, but they were mentioned only once, in day two, as something we should look up on our own :/
  • would have been nicer to actually *use* the concurrency features of language, to, idk, maybe use all the cores on your laptop to run a map/reduce job?