# Elixir

Functional highly scalable language for realtime data built on Erlang VM allowing usage of Erlang libs/functions like OTP.

Ruby on Rails-like immutable, **dynamically typed**, **functional language**

Runs inside lightweight threads(called **processes**) communicating via **messages** even if on different machines so legit horizontal scale(Erlang VM handles multi-machine, can also implement with Redis)

Elixir uses **supervisers** and processes fail fast. If there is an error, restart in proper/known state

* **Hex** package manager
* Elixir used by Brex, Tandem, Pagerduty
* Inline code tests
* Pure Functional
  * no class with internal state, but modules that init or transform an input state and return new state
  * Not indexable list, but recursive head rest pattern matching
* To dealing with state across processes, use Erlang Term Storage([ETS](http://www.erlang.org/doc/man/ets.html)) or processes like **Agents, Genserver**
* Opinated(variables **must** be camelcase and modules CamelCase)

## Basic

* Double and triple equals like javascript(type conversion vs no type conversion)
* `if age === 18 do [.] else [.] end`, ruby unless, switch => case, long if else can be cond similar to Ocaml
* Like erlang, function returns the last value
* Can't do for (int ....) b/c immutable, must use recursion
* `=` operator is actually called *the match operator*
* `someFunction/2` means someFunction with two args as functions unique by name & arg count(arity)
* `or`, `and`, `not` and can short circuit
* `==`, `!=`, `===`(doesn't count integers and floats as equal, but **works at comparing native objects! \[1,2] === \[1,2]**), `!==`, `<=`, `>=`, `<` and `>`
* Use pin operator `^` to pattern match against variables cur value: `x = 1 ^x = 2` => Error no match 1 = 2 ( apparently also used in queries for [type coercion](https://dev.to/lasseebert/til-ecto-s-pin-is-coercing-19fh))
* `"a"` is UTF-8 encoded binary while `'a'` is charlist

test.exs

```elixir
#comments
defmodule M do
	def main do
		do_stuff()		
	end
	
	def do_stuff do
		my_str = "My Sentence"
		IO.puts "Length: #{String.length(my_str)}"
		IO.puts not true
		1
	end
end
```

Doesn't actually need main or anything

#### IO

Print internal representation

```elixir
IO.inspect String.split(longer_str, " ") 
IO.write "No newline"
a = "hi"
IO.puts "Puts with newline #{a}" 
IO.puts(:stderr, "error bb")
x = IO.gets("yes or no?") #prompts user and return string with newline

(1..10)
|> IO.inspect #returns param for easy pipe usage
|> Enum.map(fn x -> x * 2 end)
```

`IO.inspect [97, 98]` => \[a,b]

`IO.inspect [97, 98], char_lists: :as_lists` => \[97, 98]

### Branches

```elixir
age = 16
if age >= 18 do
	IO.puts "Can Vote"
else #no else if
	IO.puts "Can't Vote" 
end

unless age === 18 do 
	IO.puts "You're not 18"
else 
	IO.puts "You are 18"
end
```

Trenary op

```elixir
canvote = if age > 18, do: "Can Vote", else: "Can't Vote"
if 0, do: "printed", else: "not printed" #if checks for nil or false, anything else is true
```

Conditional Matching, goes to first match

```elixir
cond do #checks list of conditions
	x -> IO.puts "You can vote"
	age >= 16 -> IO.puts "You can drive"
	age >= 14 -> IO.puts "You can wait"
	true -> IO.puts "Default"
end
```

switch

```elixir
case x do
	1 -> :one
	2 -> :two
	n when is_integer(n) and n > 2 -> :larger_than_two
end
  
case Chat.get_chat_message(message_id) do
  %ChatMessage{} = chat_message ->				  
  	Chat.delete_chat_message(chat_message)

  nil -> nil
end
```

#### With

```elixir
with {:ok, user} <- create_user(user_params),
     {:ok, email} <- Mailer.compose_email(user) do
  {:ok, Mailer.send_email}
else
  {:error, _reason} ->
    handle_error
end

with user_id when not is_nil(user_id) <- get_session(conn, :user_id),
       user when not is_nil(user) <- Repo.get(User, user_id)
  do
    assign(conn, :current_user, user)
  else
    _ ->
      conn
      |> Controller.put_flash(:error, "You have to sign in to access this page.")
      |> Controller.redirect(to: "/sign_in_links/new")
      |> halt
  end
```

In the code snippet above we've rewrite nested `case` clauses with `with`. Within `with` we invoke some functions (either anonymous or named) and pattern match on their outputs. If all matched, `with` return `do` block result, or `else` block result otherwise.

We can omit `else` so `with` will return either `do` block result or the first fail result.

### System Variables

```elixir
 System.get_env("POSTMARK_API_KEY")
```

### Type Converstion

```elixir
Integer.to_string(123) #"123"
String.to_integer("123") #123
String.to_integer("abc") #(Argument Error)
Integer.parse("123") #{123, ""}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://openai.gitbook.io/code-cheatsheets/all/elixir.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
