We're now going to better get to know the Kernel module. The Kernel module is automatically imported everywhere, so you never have to explicitly specify the Kernel module unless that's needed to resolve some ambiguity, which does happen from time to time, since many Kernel functions have the same names as Elixir operators.

The Kernel module is big, really big, so the coverage of the Kernel module will be divided more than one part. Fortunately, many of the functions require little explanation since many of them directly correspond to operators or keywords in Elixir.

In fact, it appears from what I've seen so far that most of the operators and many of the keywords in Elixir have an equivalent function in the Kernel module. The Elixir compiler almost certainly translates operators and their operands into calls to these Kernel functions.

Since I've already introduced the concepts behind many of these functions, I'm not going to go in-depth on all of them. That would be boring and pointless. I'm assuming that you've been following along from the beginning, so I don't see a need to re-explain things. I'll only go into depth for the functions where it makes sense to do so. Finally, there are some functions in the Kernel module that relate to more advanced concepts I haven't learned about yet. I'll be glossing over these for sure, since I do not yet understand them yet. If I think it's useful to do so, I may come back and look at them again after I learn about the relevant concept, but that's only if I feel that it will add something to what we've already learned.

The Arithmetic Operator Functions

These functions directly correspond to arithmetic operators in Elixir. Whenever you use one of these operators in Elixir, the compiler calls these functions.

Function Description Example Comments
*/ Multiplication 4 * 4
+/ Unary plus +3 I'm not sure why this is useful, since it doesn't appear to do anything more than echo the original value.
+/2 Addition 5 + 3
-/1 Unary minus -1 Negates a number, causing the sign to toggle
-/2 Subtraction 3 - 1
//2 Float Division 3 / 1 Result is always a float

All of these operators should be familiar to you except the unary plus. At first I thought that the unary plus function was an absolute value function, but there's already abs/1 that does that. I played around with it to get a feel for what it does, and here are the results.

iex> -1
-1
iex> -(1 + 1)
-2
iex> -(-1 + -1)
2
iex> +(1 + 1)
2
iex> +(-1 + -1)
-2
iex> +(-4)
-4
iex> +4
4

It doesn't force a number to become positive, which makes sense now that I think about it; the unary minus doesn't force a value to be negative: it just toggles the sign on the number between positive and negative. The unary plus seems to do the opposite of unary minus, which is to just return the number with the original sign. This doesn't seem very useful, but there's something I'm probably missing here. It may be useful as a predefined function to pass to a higher-order function when you don't want to modify a number, but that's the only thing I can think of.

Calling Operator Functions

Although many of the functions in the Kernel module correspond to Elixir operators, they can be called directly or passed to higher-order functions. You would normally not call these functions directly, since the operator equivalent is much nicer to use, but it is normal to pass them to higher-order functions.

If you are weird and you want to call functions that correspond to operators, be aware that they cannot be called normally, because they will be interpreted as operators and not functions in the Kernel module.

iex> +(2, 3)
** (SyntaxError) iex:8: syntax error before: ')'

iex> *(2, 3)
** (SyntaxError) iex:8: syntax error before: '*'

Instead, you must explicitly reference the Kernel module so that Elixir knows you are referring to the function directly.

iex> 2 + 3
5
iex> Kernel.+(2, 3)
5
iex> 2 * 3
6
iex> Kernel.*(2, 4)
6
iex> 2 / 3
0.6666666666666666
iex> Kernel./(2, 3)
0.6666666666666666

You don't always need to specify the Kernel module when passing the function into a higher-order function as a parameter. Since you use the capture operator (&), Elixir will know that this is a function and not an operator.

iex> Enum.reduce(1..10, &+/2)
55
iex> Enum.reduce(1..10, &//2)
4.063492063492063

The last result was a bit unexpected for me because I was expecting the result to be (((1 / 2) / 3) / 4) .... Instead, the division occurred in the opposite order, with reduce dividing the number by the accumulator and not the other way around. Reduce passes the accumulator as the second parameter, not the first. If I wanted to get what I expected, I would have to create my own function to reverse the division operands.

iex> Enum.reduce(1..10, fn (number, acc) -> acc / number end)
2.7557319223985894e-7

The result is a very small decimal. The parameter order in a reduce function can make a big difference.

Comparison Functions

These functions correspond to comparison functions that return a boolean value after comparing. If you don't remember how these comparison operators work, please refer back to Lwm 7 where I go over that.

Function Description Example Comments
!=/2 Not equals (loose) 5 != 4
!==/2 Not equals (strict) 5 !== 5.0
</2 Less than 4 < 10
<=/2 Less than or equal 5 <= 5
==/2 Equals (loose) 5 == 5.0
===/2 Equals (strict) 5 === 5
>/2 Greater than 12 > 10
>=/2 Greater than or equal 12 >= 10

Here are a few examples of calling these functions directly.

iex> Kernel.===(5, 5.0)
false
iex> Kernel.==(5, 5.0)
true
iex> Kernel.==("Blue", :blue)
false
iex> Kernel.>(3, 8)
false
iex> Kernel.>(8, 3)
true

Logical Boolean Operator Functions

These functions correspond to logical boolean operators in Elixir. If you don't remember how these operators work, please refer back to Lwm 7 where I go over that.

Function Description Example Comments
!/1 boolean not (loose) !nil
&&/2 boolean and (loose) nil && 4
and/2 boolean and (strict) true and false
not/1 boolean not (strict) not false
or/2 boolean or (strict) true or false
||/2 boolean or (loose) nil || true

Here are a few examples of calling these functions directly.

iex> Kernel.not(true)
false
iex> Kernel.and(5 > 2, 1 >= -1)
true
iex> Kernel.!(nil)
true
iex> Kernel.||(nil, true)
true

Elixir Code Construct Functions

These are functions in the Kernel module that I have lumped together in this category. These functions create Elixir code constructs such as modules, attributes, macros, named functions, and so forth. I'm not sure exactly when they are called, but I believe these functions are run when code is being loaded into the Elixir/Erlang runtime environment dynamically through IEx or via script files. I think these functions are used to translate Elixir code constructs into constructs the Erlang VM understands. They're something an interpreter would use. It's possible that compiled bytecode may use these as well, but I think compiled bytecode will more likely use the equivalent Erlang VM operations. I could also see these functions being used in someone's code for creating modules and functions at runtime, but that would not be something that was typically done.

This category of functions and the way the functions are used is a little mysterious to me, and I do not wish to attempt to call them directly at this point in my learning of Elixir. I think these are a candidate for revisiting in more detail once I have gained an advanced understanding of Elixir.

I'm going to summarize them for now. Some of them are related to concepts I haven't learned yet, and I'll make a note of those when I see them.

Function Description Comments
@/1 Defines a module attribute
alias!/1 Creates an alias in a macro I don't understand what this is used for, since I haven't learned about macros yet.
apply/2 Calls a function with arguments I could see this possibly being useful on occasion when the function to be called isn't known ahead of time. It's also a candidate for passing to a higher-order function.
apply/3 Calls a function in a module with arguments
binding/1 Returns the binding for a context I have no idea what this means at this point. Perhaps it's something to do with scoping.
def/2 Defines a function
defdelegate/2 Defines a function that delegates to a function in another module I believe this corresponds to a defdelegate keyword, but I haven't learned anything about that yet. I find the concept of function delegation to be interesting
defexception/1 Defines an exception type
defguard/1 Defines a macro for use in guard expressions
defguardp/1 Defines a private macro for use in guard expressions
defimpl/3 Defines an implementation of a protocol I have not learned about protocols yet
defmacro/2 Defines a macro I have not learned about macros yet
defmacrop/2 Defines a private macro
defmodule/2 Defines a module
defoverridable/1 Makes certain functions overridable by outside code I had no idea this was possible, but it's an interesting idea. Hopefully, I'll find out more about this
defp/2 Defines a private function
defprotocol/2 Defines a protocol
defstruct/1 Defines a struct
if/2 Defines an "if" expression
in/2 Corresponds to the "in" operator
unless/2 Defines an "unless" expression
use/2 Imports the module into the current context, calling any magic initialization code in the module We call this function every time we put a "use" statement at the top of our code
var!/2 The documentation says something about not hygenizing a variable that doesn't make sense to me. I suspect that this somehow has a role in macros, which I know nothing about yet
|>/2 Corresponds to the pipe operator

Type Functions

These are functions that check to see if something is of a particular type. I covered most of these in lwm 6 where I discussed data types. I believe that all of these can be used in guard clauses.

Function Description Comments
is_atom/1 Checks to see if something is an atom
is_binary/1 Checks to see if something is a binary
is_bitstring/1 Checks to see if something is a bitstring
is_boolean/1 Checks if something is a boolean
is_float/1 Checks if something is a float
is_function/1 Checks if something is a function
is_function/2 Checks if something is a function with a particular arity
is_integer/1 Checks if something is an integer
is_list/1 Checks if something is a list
is_map/1 Checks if something is a map
is_nil/1 Checks if something is nil
is_number/1 Checks if something is a number A number can be an integer or float
is_pid/1 Checks to see if something is a pid I haven't yet learned what a pid is, other than knowing it stands for "process identifier"
is_port/1 Checks to see if something is a port I haven't yet learned what a port is in the context of Elixir
is_reference/1 Checks to see if something is a reference I haven't yet learned what a reference is in the context of Elixir
is_tuple/1 Checks to see if something is a tuple

I'm going to try out some of the functions I haven't had much opportunity to use before.

iex> is_list([])
true
iex> is_list(3)
false
iex> is_map([])
false
iex> is_map(%{})
true
iex> is_nil([])
false
iex> is_nil(0)
false
iex> is_nil(nil)
true
iex> negate = fn number -> -number end
#Function<6.99386804/1 in :erl_eval.expr/5>
iex> add = fn (num1, num2) -> num1 + num2 end
#Function<12.99386804/2 in :erl_eval.expr/5>
iex> is_function(negate)
true
iex> is_function(add)
true
#negate is a function with an arity of 1
iex> is_function(negate, 1)
true
iex> is_function(negate, 2)
false
#add is a function with an arity of 2
iex> is_function(add, 1)
false
iex> is_function(add, 2)
true
iex> is_tuple({})
true
iex> is_tuple([])

Sigil Functions

I've previously covered sigils in lwm 41, so I won't go into detail here. Each sigil has a corresponding function in the Kernel module

Function Description Comments
sigil_C/2 corresponds to the ~C sigil Creates a character list without interpolation
sigil_D/2 corresponds to the ~D sigil Creates a date value
sigil_N/2 corresponds to the ~N sigil Creates a naive datetime value
sigil_R/2 corresponds to the ~R sigil Creates a regular expression without interpolation
sigil_S/2 corresponds to the ~S sigil Creates a string without interpolation
sigil_T/2 corresponds to the ~T sigil Creates a time value
sigil_W/2 corresponds to the ~W sigil Creates a word list without interpolation
sigil_c/2 corresponds to the ~c sigil Creates a character list with interpolation
sigil_r/2 corresponds to the ~r sigil Creates a regular expression with interpolation
sigil_s/2 corresponds to the ~s sigil Creates a string with interpolation
sigil_w/2 corresponds to the ~w sigil Creates a word list with interpolation

I'm uncertain as to how to call these functions directly, since it's not even clear what needs to be passed as parameters. Even the examples in the sigil functions' documentation just show examples of using the sigil, and not calling the sigil functions. I don't think it's important to know how to either: the sigils themselves are just fine.

Process Functions

I am aware of Elixir processes and have a basic idea of how they work, which I talked about in lwm 2. The Kernel module contains some functions that work with processes. I'm just going to give a summary of what they do. I assume I'll understand these functions better after I've gained a good understanding of Elixir processes.

Function Description Comments
self/0 returns pid of current process pid is short for process identifier
send/2 sends a message to a destination, which could be another process or other things that I'm unclear about
spawn/1 spawns a function as new process and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
spawn/3 spawns a function from a module as new process and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
spawn_link/1 spawns a function as new process, linking it to the current process, and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
spawn_link/3 spawns a function from a module as new process, linking it to the current process, and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
spawn_monitor/1 spawns a function as new process, monitors it, and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
spawn_monitor/3 spawns a function from a module as new process, monitors it, and returns the pid Documentation recommends not using any of the spawn functions directly, as there are higher-level abstractions that make life a lot easier for the developer
exit/1 Stops the current process This can be used to exit your application immediately, assuming that your application only consist of a single process

Exception Functions

I previously covered exceptions in lwm 48, so I will just list the exception-related functions and write a brief summary of what they do. Other than the "reraise" function, these functions are all covered in the section on exceptions.

Function Description Comments
raise/1 raises an exception
raise/2 raises an exception
reraise/2 re-throws an exception, preserving the original stack trace This is equivalent to using the "throw" keyword in C# without any arguments
reraise/3 re-throws an exception, preserving the original stack trace This is equivalent to using the "throw" keyword in C# without any arguments
throw/1 creates a non-local return from a function, used as part of exception handling I have no idea what this means. See the exception handling post where I talk about this keyword

All the reraise functions do is throw the original exception with the original call stack trace. It allows you to intercept an exception, do something, and then let it continue flying up the call stack as if it had never been caught.

That's all we're going to cover today. Despite the Kernal module being huge, I we managed to cover the majority of the functions. As usual, I'm going to switch to another topic next time to prevent monotony, but when I come back to this topic, I'm going to go in depth into the functions I think deserve more explanation and examples.