In my post Starting out with Elixir I started out looking at how to create a basic Elixir file then looked at mix to generate a project.
Again, I’m not going to go into any depth on the Elixir language, there’s no way I could cover it, but let’s look at modules and functions.
NOTE: I’m new to Elixir, so take all information in this post as me learning things – there may be better ways or different ways to do things that I’ll learn later. This is all about getting a grounding in some basic concepts.
Modules
Like modules or namespaces in other languages, Elixir has the module concept for grouping together functions. For example when using IO.puts, IO is the module and the function is puts
To declare a module we write the following
defmodule Module.Name do # your functions end
The module name can have a full stop/period in the names. The module’s first letter should be uppercase. We can group together functions within a module including private functions.
Functional means functions
Writing anything but the simplest applications/code requires the need for functions. Elixir is a functional language so let’s create some.
Named functions are defined using the following format and should be placed within a module and the function name should start with a lowercase letter, for example
defmodule Simple.Messages do def say_hello() do "Hello World" end end
Like other functional languages we can just have the return value as the last line of the function. So in this example we are returning a string “Hello World”.
We could rewrite the above function like this as a one liner
def say_hello(), do: "Hello World"
Actually we can using a syntax such as
def say_hello(), do: ( "Hello World" )
and having multiple lines within the ( … ) parenthesis, the def … end style shown initially is a syntactic sugar way of declaring your functions.
We pass parameters in the “standard” way, within the parenthesis of the function and we can supply default values. Like other functional languages, we do not need to define the types of parameters, these are inferred (again, pretty standard in the functional world).
def say_hello(name), do: "Hello #{name}"
We can create function overloads, i.e. functions with the same name but different arity (number of parameters or arity). The example above also shows string interpolation using #{} syntax.
Here’s an example with a default parameter (obviously this will display a warning if you have a parameter-less function of the same name
def say_hello(name \\ "World"), do: "Hello #{name}"
We can also create anonymous functions, for example
anon = fn (name) -> "Hello #{name}" end # calling the function is slightly different to named functions IO.puts anon.("Scooby")
There’s also a shorthand for such functions where we denote that parameters using $ followed by the parameter index, i.e.
anon = &("Hello #{&1}") IO.puts anon.("Scooby")
As mentioned in the modules section, we can also create private functions and these are declared using defp like this
defp say_hello(name), do: "Hello #{name}" def say_hello_scooby(), do: say_hello("Scooby")
In this example say_hello is private and say_hello_scooby is public.
Aliasing module names
In some cases we might want to alias a module. For example out Simple.Messages module might be alias within another module, where by
defmodule HelloWorld.Application do alias Simple.Messages def run() do IO.puts Message.say_hello("Scooby") end end
Notice we no longer need to fully qualify the module name when it’s used.
That should be enough to get one started writing modules and functions, I’m sure I’ll create other posts to explore how these work further at some point.