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.
- 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 (!)
- 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
- 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
- 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?