Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Elixir 101: Extras

Elixir_101_extras.livemd

Elixir 101: Extras

Kernel & Kernel.SpecialForms

Kernel

Kernel.SpecialForms

Structs… continued

underneath a struct...

although structs are maps...

defmodule User do
  defstruct [:name]
end

User |> Map.from_struct()
{:ok, val} = %{a: 7} |> Map.fetch(:a)
val
{:ok, name} = %User{name: "Shaniqua"} |> Map.fetch(:name)
name
{:ok, name} = %User{} |> Map.fetch(:name)
name
:error = %User{} |> Map.fetch(:field_without_a_key_in_a_user_struct)

The double equals (==) equality operator tests for equality of left-hand and right-hand side values

The single equals (=) match operator tries to match whatever is on the left-hand side with whatever is on the right-hand side

%User{} generates a User struct with the default values for the User struct keys

The following creates identical structs and tests whether they’re equal using the == operator

%User{} == %User{name: nil}
%User{name: "john"} |> Map.from_struct()
%User{name: "john"} |> Map.from_struct() |> (fn map -> struct(User, map) end).()
%User{name: "john"} |> Map.from_struct() |> (&struct(User, &1)).()

Pattern Matching != Assignment (redux)

y = 3

Erlang is immutable and will NOT allow you to rebind a variable to a new value. Erlang “variables” really aren’t variables, they’re effectively constants.

Elixir data structures are immutable, but an Elixir variable (which can point at an Elixir data structure) can be re-bound to point at a different data structure.

You can, for example, re-bind the left-hand side variable to the evaluated value of the right-hand side, even if the left-hand side variable is currently equal to a different value.

y = y + 1

When you do this, however, the underlying data structure does NOT change. So if anyone else holds another reference to that data structure, their reference will still point at the original data structure.

In this example, the “data structure” is just an integer, but you can see that the value of b does not change when the value of a changes, even though they initially pointed at the very same data structure (i.e., the value 7).

a = b = 7
"a = #{a}, b = #{b}"
a = 8
"a = #{a}, b = #{b}"

To prevent re-binding a variable and insist on matching against a variable’s current value, we use “the pin operator” (^).

The pin operator prevents variable re-binding.

If a match succeeds, the result of evaluating the line is the value of the right-hand side.

^y = 4

If attempting to pattern match fails, a MatchError is generated:

# Since `y` is currently bound to the value 4, this pattern-match will fail with a `MatchError`:
#    "** (MatchError) no match of right hand side value: 5"

^y = 5
z = 5
^z = 5
x = %{1 => "a", 2 => "b", 3 => "c"}

Because x is equal to that map, you can now also successfully pattern-match in the opposite direction:

%{1 => "a", 2 => "b", 3 => "c"} = x

Extracting values from Maps

x[1]
Map.get(x, 2)

The following will all successfully pattern-match because everything on the left-hand side of the match operator (i.e., “=”) is present and identical on the right-hand side:

%{1 => "a", 2 => "b", 3 => "c"} = %{1 => "a", 2 => "b", 3 => "c"}
%{1 => "a", 2 => "b"} = %{1 => "a", 2 => "b", 3 => "c"}
%{3 => "c"} = %{1 => "a", 2 => "b", 3 => "c"}
%{} = %{1 => "a", 2 => "b", 3 => "c"}

The following will all FAIL to pattern-match (raising MatchErrors) because something on the left-hand side is either not present on the right-hand side or is different on the right-hand side:

# These will all fail with an "(MatchError) no match of right hand side value" error message

# %{1 => "a", 2 => "b", 3 => "c"} = %{1 => "a", 2 => "b"}
# %{1 => "a", 2 => "c"} = %{1 => "a", 2 => "b"}
# %{1 => "a", 2 => "c"} = %{1 => "a"}
# %{1 => "b"} = %{1 => "a"}
%{1 => "b"} = %{}

We can extract desired values into named variables via pattern-matching:

%{3 => value_of_3} = %{1 => "a", 2 => "b", 3 => "c"}

value_of_3

Documentation

Elixir documentation is amazing, but you’ll want to become comfortable surfing it for what you need because functions & macros can live in nooks and crannies.

Kernel.struct/2

I’ve just started using the Dash code browser (NOT FREE: $30).

I prefer free & open-source tools (and have used tools like DevDocs/DevDogs):

But Dash is cool because it lets me search Elixir docs, Erlang docs, and even Hex packages, like Phoenix.

I have no relationship with Kapeli, other than just having bought it.

Dash

Elixir & Erlang docs are searchable!!!

  • Typing “erl:” scopes your queries to just Erlang docs
  • Typing “elixir:” scopes your queries to just Elixir docs

Erlang docs

binary_to_term

universaltime

And ALL Hex docs are downloadable & (then) searchable!!!

  • Typing “hex:” scopes your queries to Hex packages you have already downloaded

Phoenix docs too

Many thanks to those developers who have improved Elixir & Erlang’s documentation and helped to standardize them!!!

Thanks, EEF

Superheroes