Elixir Gotchas
28 Sep 2020
.ex vs .exs
- .ex - compiled
- .exs - interpreted (don't need to be compiled for each change)
use vs import vs require vs alias
- Use - gives full control to another module and calls its __using__ macro
- Import - references a function from another module with its name only
- Require - ensures a module is compiled first (needed if they contain macros)
- Alias - creates additional names for modules (useful for lengthy module names)
Accessing Collection Elements
We can access map values with the access operator.
> user = %{name: "example", email: "example@example.com"} > user[:name] "example"
The access operator does not work on regular lists or tuples.
> list = ["a","b","c"] > list[1] ** (ArgumentError) the Access calls for keywords expect the key to be an atom, got: 1 (elixir 1.10.4) lib/access.ex:311: Access.get/3
Accessing list elements is done with Enum library functions.
> list = ["a","b","c"] > Enum.at(list, 1) "b" > Enum.fetch(list, 1) "b" > Enum.fetch!(list, 1) "b"
Enum.fetch/2 will return :error if the given index is out of bounds.
> Enum.fetch(list, 3) :error
Enum.fetch!/2 will throw an error if the given index is out of bounds.
> Enum.fetch!(list, 3) ** (Enum.OutOfBoundsError) out of bounds error (elixir 1.10.4) lib/enum.ex:881: Enum.fetch!/2
The access operator does work on keyword lists.
> list = [name: "bob"] > list[:name] "bob"
Anonymous Functions
Anonymous function declarations begin with fn and end with end.
A common mistake is forgetting the end token.
> hello = fn x -> IO.puts "hello, #{x}" end
Anonymous functions are invoked with the dot operator.
> hello.("world") hello, world
Module Attributes
Modules can contain something that looks like instance variables from Ruby.
These are called module attributes.
defmodule Example do @default_config %{format: "txt", tabs: false} @moduledoc """ Documentation for `Example`. """ end
They can be read but not modified at runtime.
Default Parameters
Default parameters are denoted with \\ instead of =.
def hello(str \\ "world") do IO.puts "hello, #{str}" end
Structs
Elixir provides a type of map with compile-time checks called a struct.
defmodule User do defstruct username: "example", email: "example@example.com" end
> user = %User{}
Although a struct looks similar to a map, we cannot access its values with the access operator.
> user[:email] ** (UndefinedFunctionError) function User.fetch/2 is undefined (User does not implement the Access behaviour) (http_test 0.1.0) User.fetch(%User{email: "example@example.com", username: "default_username"}, :email) (elixir 1.10.4) lib/access.ex:286: Access.get/3
Instead we use the dot operator.
> user.email "example@example.com"