Learn With Me: Elixir - The Kernel Module Part 4 (#62)

I'm going to take a break from talking about Elixir projects and applications to go over a few more functions in the Kernel module. I'm going to cover two more categories of functions: binary functions and math functions.

Binary Functions

These are the Kernel module functions that deal with binaries.

Kernel.<>/2

The Kernel.<>/2 function corresponds to the binary concatenation operator <>. It takes in two binaries and returns the two binaries concatenated together. In practice, the binaries will mostly be strings, but any binaries will work. You're most likely going to be using the operator rather than calling the function directly, but it's there if you need to pass it into a higher-order function.

iex> Kernel.<>("My name is ", "Ursula")
"My name is Ursula"
iex> "My name is " <> "Ursula"
"My name is Ursula"
iex> Kernel.<>(<<4, 3, 64>>, <<3, 0, 12, 43>>)
<<4, 3, 64, 3, 0, 12, 43>>
iex> Enum.reduce(["a", "b", "c", "d", "e"], "", &Kernel.<>/2)
"edcba"

Kernel.binary_part/3

The Kernel.binary_part/3 function extracts a section of a binary. It's like a substring operation, but it can be used with any binary. The first parameter is the binary, the second parameter is the starting index, and the third parameter is the length of the section to be extracted.

If either the start or length parameters go beyond the bounds of the binary, an ArgumentError is thrown.

This function can be used in a guard clause.

There is also a String.slice/3 function that is very similar to this one. The difference is that String.slice/3 operates on characters (code points) whereas Kernel.binary_part/3 operates on bytes. It's possible to split a binary in the middle of a multi-byte UTF-8-encoded character using Kernel.binary_part/3, but that would not be possible with String.slice/3.

iex> binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 3, 4)
<<4, 5, 6, 7>>
iex> binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 0, 0)
""
iex> binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 0, 1)
<<1>>
iex> binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 10, 1)
** (ArgumentError) argument error
    :erlang.binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 10, 1)
iex> binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 5, 10)
** (ArgumentError) argument error
    :erlang.binary_part(<<1, 2, 3, 4, 5, 6, 7, 8>>, 5, 10)
iex> binary_part("string", 0, 1)
"s"
iex> binary_part("string", 2, 1)
"r"

Kernel.bit_size/1

The Kernel.bit_size/1 function returns the number of bits in a binary.

This function can be used in a guard clause.

iex> bit_size(<<3, 9, 134, 12, 22>>)
40
iex> bit_size(<<3, 9, 134, 12, 22, 9>>)
48
iex> bit_size(<<3, 9, 22, 9>>)
32
iex> bit_size(<<7>>)
8
iex> bit_size(<<>>)
0
iex> bit_size("This is a string")
128

Kernel.byte_size/1

The Kernel.byte_size/1 function returns the number of bytes in a binary. If the number of bits is not divisible by 8, which can be the case if the binary is a bitstring, it will be rounded up.

This function can be used in a guard clause.

iex> byte_size(<<3, 9, 134, 12, 22>>)
5
iex> byte_size(<<3, 9, 134, 12, 22, 9>>)
6
iex> byte_size(<<3, 9, 22, 9>>)
4
iex> byte_size(<<7>>)
1
iex> byte_size(<<>>)
0
iex> byte_size("This is a string")
16
#This is 26 bits, so is rounded up to 32 bits (4 bytes)
iex> byte_size(<<3, 4::6, 6::12>>)
4
#This is 6 bits, so is rounded up to 8 bits (1 byte)
iex> byte_size(<<3::6>>)
1

Math Functions

These are various functions in the Kernel module functions that deal with numbers. I've grouped them together and called them "math" functions, but that's just my personal labelling in an attempt to group all the functions in the Kernel module.

Kernel.abs/1

The Kernel.abs/1 returns the absolute value of a number, which can be an integer or float.

This function can be used in a guard clause.

iex> abs(-5)
5
iex> abs(-1)
1
iex> abs(0)
0
iex> abs(2)
2
iex> abs(2.3)
2.3
iex> abs(-2.875)
2.875

Kernel.div/2

The Kernel.div/2 function performs integer division. Any remainder is discarded. This has the effect of rounding down for positive numbers and rounding up for negative numbers (rounding towards 0). Division by 0 will of course result in an error. Only integers can be passed as parameters.

This is works just like division in C++ or C# when two integers are involved.

This function can be used in a guard clause.

iex> div(8, 4)
2
iex> div(8, 3)
2
iex> div(8, 2)
4
iex> div(-8, 4)
-2
iex> div(-8, 3)
-2
iex> div(10, 3)
3
iex> div(0, 3)
0
iex> div(3, 0)
** (ArithmeticError) bad argument in arithmetic expression: div(3, 0)
    :erlang.div(3, 0)
iex> div(2.3, 1.2)
** (ArithmeticError) bad argument in arithmetic expression: div(2.3, 1.2)
    :erlang.div(2.3, 1.2)

Kernel.rem/2

The Kernel.rem/2 function gives us the remainder after integer division has been performed. It's equivalent to the modulo operator % in Javascript and C#. This particular function has already been used a lot in prior examples.

If we are dividing by a number, then the remainder must fall in the range 0 to number - 1. If we divide by two, we can look at the remainder to determine if a number is even or odd.

This function can be used in a guard clause.

iex> rem(8, 2)
0
iex> rem(8, 3)
2
iex> rem(8, 4)
0
iex> rem(8, 5)
3
iex> rem(10, 3)
1
iex> rem(10, 2)
0
iex> rem(11, 2)
1
iex> rem(12, 2)
0

Kernel.round/1

The Kernel.round/1 function rounds a number to the nearest integer.

This function can be used in a guard clause.

iex> round(1)
1
iex> round(1.1)
1
iex> round(1.4)
1
iex> round(1.5)
2
iex> round(1.9)
2
iex> round(2.5)
3
iex> round(-2.5)
-3
iex> round(-2.4)
-2
iex> round(0.4999999)
0
iex> round(0.9999999)
1

Kernel.trunc/1

The Kernel.trunc/1 function truncates a number. That means that the non-integer part of the number is discarded and the integer part is returned.

This function can be used in a guard clause.

iex> trunc(3)
3
iex> trunc(3.14)
3
iex> trunc(3.9)
3
iex> trunc(-2)
-2
iex> trunc(-2.3)
-2
iex> trunc(-2.9)
-2

Kernel.floor/1

The Kernel.floor/1 function always rounds a number down to the nearest integer, unless the number is an integer already. In the words of the documentation, it returns "the largest integer not greater than the number passed to the function". This is the same behavior as Kernel.trunc/1 for positive numbers, but it differs for negative numbers.

This function can be used in a guard clause.

iex> floor(3)
3
iex> floor(3.14)
3
iex> floor(3.9)
3
iex> floor(0)
0
iex> floor(-2)
-2
iex> floor(-2.3)
-3
iex> floor(-2.9)
-3

Kernel.ceil/1

The Kernel.ceil/1 function is the opposite of Kernel.floor/1. It always rounds the number up to the next highest integer, unless the number is an integer already. In the words of the documentation, it returns "the smallest integer greater than the number passed to the function". This is the same behavior as Kernel.trunc/1 for negative numbers, but it differs for positive numbers.

iex> ceil(3)
3
iex> ceil(3.14)
4
iex> ceil(3.9)
4
iex> ceil(0)
0
iex> ceil(-2)
-2
iex> ceil(-2.3)
-2
iex> ceil(-2.9)
-2

Conclusion

That's it for today. We still have a lot of functions remaining in the Kernel module, and we'll eventually cover them all. No hurry, they'll be there waiting for us