Photo by Tim Mossholder on Unsplash
3 min read
The best programming book I've read was Atomic Scala by Bruce Eckel and Dianne Marsh. It was so good that when I went for a job interview I chose to use Scala for the technical test because I was so in love with the language and its programming concepts. Well, that was premature and I bombed the interview but I'm still fond of the book and Scala.
As I learn Elixir, what I'm coming across in the literature doesn't fill me with the same excitement. I've read about Elixir structs, maps, lists and pattern matching too many times. I want to get to a working knowledge of the language and at this point, I don't really care if strings are UTF-8, how large a float is or the Erlang representation behind them.
When I'm on holiday in Spain, what I care about is how to say "Good morning, table for two please" not "Spanish is a Romance language that originated in the Iberian Peninsula and today has over 450 million native speakers in Spain and the Americas. It is a global language and the world's second-most spoken native language, after Mandarin Chinese".
So this is an ode to Atomic scala.
Methods aka. Function aka. Do something
A method groups programming logic that can be executed by name or anonymously. Simple functions are used to build more complex logic structures. You don't need a
- Arity - the number of parameters to a method e.g
List.first/1means one parameter required for the function named
- Typedef - i.e.
@spec- explicit type information used to find errors. Learn more
- Pattern matching - the method signature is determined by the type of arguments
- Guard - a conditional that is checked before executing a function. Learn more
- Default value - i.e.
argument \\ value
Named functions exist in modules and have the structure:
defmodule Module_name do # note the comma before 'do' def function_name (arg1), do ... end @spec function_name(type()) :: return_type() def function_name (arg1, arg2) when arg1 > 0 do ... end end
Private functions start with
defp instead of
Anonymous functions have two structures with
function_name = fn (arg1, arg2) -> ... end capture_function = &(&1 ... &2)
A header function is a function with the same name as a named function and is used to set the default value for the named function's argument(s). E.g.
defmodule Module_name do def function_name(arg1 \\ default_value) def function_name(arg1), do ... end end
@spec multiply(number()) :: number() defmodule Calculator do def multiply(arg1, arg2) when arg1 > 0 do arg1 * arg2 end end Calculator.multiply(0, 2) # -> (FunctionClauseError) no function clause matching in Calculator.named_multiply/2 Calculator.multiply(2, 3) # -> 6 anon_multiply = fn (arg1, arg2) -> arg1 * arg2 end capture_multiply = &(&1 * &2) anon_multiply.(2, 4) # -> 8 capture_multiply.(5, 4) # -> 20 defmodule Greeter do def hello(name \\ "world") def hello(names) when is_list(names) do names |> Enum.join(", ") |> hello end def hello(name) when is_binary(name) do phrase() <> name end def phrase, do: "Hello, " end Greeter.hello() # -> "Hello, world" Greeter.hello("Mark") # -> "Hello, Mark" Greeter.hello(["Mark", "Luke"]) # -> "Hello, Mark, Luke"