Elixir basic types 🧪
Tags: elixir, webdev, tutorial
Published: 2021-01-02 09:11:49

Data types specify what kind of data can be stored and manipulated within a program. Here we don't cover types related to time (`Time`, `Datetime`).

**Briefly intro table:**

|Type   |Example   |
|---|---|
|Integer   |`34`   |
|Float   | `34.02`  |
| Boolean  | `true/false`  |
| String  | `"Ama string"`  |
| Charlist  | `'Erlang'`  |
| Atom  | `:ok  / :error`  |
| List  | `[40123, false, :ok]`  |
| Tuple  | `{40, true, "cat"}`  |
| Map  | `%{name: "Tom", city: "New York"}`  |
| Range  | `1...100`  |
| Regexp | `~r/[0-9]+\.[0-9]*/` |
                                                     
**Table of contents:**
* Integer
* Float
* Boolean
* Atom
* String
* Charlist
* Binaries
* Lists and tuples
* Map
* Ranges
* Regexp

### Integers

Numbers without fractional part. Same to any other language. `Integer` in Elixir can hold any arbitrary integer (so you don't have int32, long and etc.)
```elixir
1
2
3
```

Elixir provides an interesting representation of numbers with underscore similar to Ruby. It's more readable for large numbers.

```elixir
34_453_234_984

# => 34453234984
```

### Float

Computers use a binary system, so they can't natively represent decimal numbers. Some languages have their own solutions like the `BigDecimal` type in Java or `Rational` in Ruby. Elixir now contains only float and integer.

Because it is a binary representation of the base 10 system, you get inaccurate results when performing mathematical operations with a "big" fractional part.

```elixir
0.123123127312631872653718290312312312312
# => 0.12312312731263188
```

If you are interested, you can read more about floating-point math [here](https://0.30000000000000004.com/).

If you need high accuracy calculations, you can use [decimal implementation package](https://github.com/ericmj/decimal)

### Boolean

The Boolean data type can hold only two values: true or false. It is typically used to store values like yes (true) or no (false), on (true) or off (false), etc., as demonstrated below:

```elixir
ready? = true
failed? = true
done? = true
```

### Atom 
Atoms are constants whose values are their name; it's similar to the symbol type in Ruby lang.

Atoms are equal if their symbols are equal.

```elixir
:no == :no
# => true

:no == :yes
# => false
```

They are handy in a situation when you want to express the state of operation, the classic ones :ok and :error

True and false are also atoms, watch the example below:

```elixir
true == :true
# => true
is_atom(false)
# => true
is_boolean(:false)
# => true
```

> Remark 📝 
> 
> Because atoms are immutable and created globally for all virtual machine, they are very effective.

### String

```elixir
"Dog"
# => "Dog"
"Car"
# => "Car"
```

A double-quoted Elixir string is actually encoded as `UTF-8`, and the bytes of the string are stored as a binary data type. So when you're working with a string, you're actually working with a binary. A binary is a data type that stores a sequence of bytes.

```elixir
is_binary("Dog")
# => true
```

### Charlist

Character lists are a special kind of list that is used to store characters. A character list literal is a string of text surrounded by single quotes. The primary use of character lists is to communicate with Erlang functions, which use character lists instead of Elixir strings.

```elixir
'This is a character list'
```

### Binaries

Binaries are sequences of bytes enclosed in `<< >>` separated with a comma. For example,

```elixir
<< 65, 68, 75>>
# => "ADK"

is_binary(<< 65, 68, 75>>)
# => true
```

### List and Tuple

First, take a look at lists. Elixir uses square brackets to specify a list of values. Values can be of any type. For example,

```elixir
[1, "Hello", :an_atom, true]

hd([1, "Hello", :an_atom, true])
# => 1

tl([1, "Hello", :an_atom, true])
# => true
```

When Elixir sees a list of printable ASCII numbers, Elixir will print that as a charlist (literally a list of characters). 

```elixir
[104, 101, 108, 108, 111]
# => 'hello'
```

Charlists are quite common when interfacing with existing Erlang code. Whenever you see a value in IEx and you are not quite sure what it is, you can use the i/1 to retrieve information about it:

```elixir
[104, 101, 108, 108, 111]
# => 'hello'

i 'hello'
Term
  'hello'
Data type
  List
Description
  ...
Raw representation
  [104, 101, 108, 108, 111]
Reference modules
  List
Implemented protocols
```

Elixir uses curly brackets to define tuples. Like lists, tuples can hold any value.

```elixir
{ 1, "Hello", :an_atom, true }
```

So, what's the difference and when to use tuple and when list? 

* Lists are actually stored as [linked lists](https://en.wikipedia.org/wiki/Linked_list), so insertions, deletions are very fast for tail and head. 
* Tuples, on the other hand, are stored in a contiguous memory block, which makes accessing them faster and the size of the tuple is also faster. However, updating or adding elements to tuples is expensive because it requires creating a new tuple in memory.

|Operation|List   |Tuple   |
|---|---|---|
|Insertion/deletion in head|✅| ❌  |
|Insertion/deletion in tail|✅   |❌   |
|Size of collection|❌   | ✅  |
|Accessing element in the middle of collection|❌ |✅ |


### Map

Store an unordered collection of key-value pairs. In the next chapters, we'll look more closer to Map.

```elixir
%{name: "BMV", type: "car"}
```

### Ranges

It's something similar to ruby, but it works only with integers. So, in a nutshell, it's just an increasing or decreasing sequence of integers. Range is enumerable, so you can iterate over it.

```elixir
1..100
# => 1..100
```

> Remark 📝 
> 
> Range is a lazy collection; each element in the range is generated as the range is iterated over.

### Regexp

Regular expressions are patterns used to match character combinations in strings.

Regex is based on PCRE (Perl Compatible Regular Expressions) and built on top of Erlang's `:re` module, say hello to Ruby. More information can be found in the `:re` [module documentation](https://erlang.org/doc/man/re.html).

```elixir
regex = ~r/[0-9]+\.[0-9]*/

Regex.match?(regex, "0")
# => false

Regex.match?(regex, "1230.4653")
# => true
```