# Basic Types and Immutability — Elixir & Phoenix

Source: https://www.geekswithgeeks.com/en/elixir-phoenix/f-types

> Use atoms, numbers, strings, lists, tuples, maps and keyword lists.

## Elixir's data types

**Integers** have arbitrary precision and **floats** are 64-bit; `/` always returns a float, while `div` and `rem` do integer division. **Atoms** are named constants whose value is their name (`:ok`, `:error`, `:pending`); `true`, `false` and `nil` are atoms too, and module names are atoms. **Strings** are UTF-8 binaries in double quotes with interpolation (`"Hi #{name}"`); `String.length` counts characters while `byte_size` counts bytes. Single-quoted `'abc'` is a **charlist** (a list of code points), mainly for Erlang interop, and is written `~c"abc"` in modern code. **Lists** `[1, 2, 3]` are linked lists, fast to prepend with `[0 | list]` and slow to index. **Tuples** `{:ok, value}` are fixed-size, contiguous and used for return values. **Maps** `%{"pune" => 2}` or `%{city: "Pune"}` are key-value stores, accessed with `map.city` (atom keys, raises if missing) or `map[:city]` (returns nil). **Keyword lists** `[timeout: 5000, retries: 3]` are lists of `{atom, value}` tuples used for options. All data is **immutable**: functions return new values, and rebinding a variable name does not change the old value.

## Working with basic types

Atoms, maps, tuples and immutable updates.

```elixir
status = :paid
IO.puts(status == :paid)                 # true

IO.puts(7 / 2)                            # 3.5 (always a float)
IO.puts(div(7, 2))                        # 3
IO.puts(rem(7, 2))                        # 1

name = "Ananya"
IO.puts("Hello #{name}")
IO.puts(String.length("नमस्ते"))           # characters
IO.puts(byte_size("नमस्ते"))               # bytes

order = %{id: "o-1", city: "Pune", total: 1200}
IO.puts(order.city)                       # Pune
IO.inspect(order[:discount])              # nil

updated = %{order | total: 1500}          # update an existing key (new map)
with_note = Map.put(order, :note, "gift") # add a key (new map)
IO.inspect(order.total)                   # still 1200: data is immutable

items = ["pen", "ink"]
more = ["pad" | items]                    # prepend: ["pad", "pen", "ink"]

result = {:ok, updated}
opts = [timeout: 5_000, retries: 3]
IO.inspect(Keyword.get(opts, :retries))   # 3
IO.inspect(with_note)
IO.inspect(more)
IO.inspect(result)
```

## Rebinding is not mutation

`x = 1` followed by `x = 2` rebinds the name `x` to a new value. Any closure or process that captured the old value still sees 1. Values themselves never change.

**Quiz:** What does `%{order | total: 1500}` do?

- [ ] Mutates order in place
- [ ] Adds a new key only
- [x] Returns a new map with total updated, raising if total is not already a key
- [ ] Deletes the total key

*Answer:* Returns a new map with total updated, raising if total is not already a key. The update syntax creates a new map and requires the key to exist.
