Skip to content

Instantly share code, notes, and snippets.

@kevinmarquesp
Last active June 24, 2024 02:00
Show Gist options
  • Save kevinmarquesp/41a8a690d784b8a808450ec6e57edd08 to your computer and use it in GitHub Desktop.
Save kevinmarquesp/41a8a690d784b8a808450ec6e57edd08 to your computer and use it in GitHub Desktop.
Lista de conceitos que fui escrevendo e colando no terminal rodando om IEX pra entender, certinho, como funciona um GenServer por baixo dos panos.
# Concept 1:
# Elixir can spawn process to run functions.
spawn(fn ->
"Hello world!"
end)
# Concept 2:
# Elixir can send messages to other process, including the current IEX one.
# At the same time, it can stop the runtime and wait to recieve a message
# sent to other process.
mypid = self()
send(mypid, {:info, "Hello world!"})
receive do
{:info, msg} ->
IO.puts(msg)
end
# Alternative that waits some seconds before sending a message.
mypid = self()
Process.send_after(mypid, {:info, "Hello world!"}, 5000)
receive do
{:info, msg} ->
IO.puts(msg)
end
# Therefore:
# It's possible to create a module that can send stuff to other process and
# receive messages at the same time.
defmodule Person do
@doc """
When created a new function, it will run the listen function of the package
specified **in background**, it will return the PID of that process.
"""
def new() do
spawn(Person, :listen, [])
end
@doc """
This will keep listening to messages and executing some code based on what
is received. That's why it was the function choosen to be ran in a background
process.
"""
def listen() do
receive do
{:msg, message} ->
## threat this block as an method of an object.
IO.puts("Someone said to me \"#{message}\" right now!")
end
listen()
end
end
# User's API for that kind of module.
bob_pid = Person.new()
send(bob_pid, {:msg, "Hello bob!"})
# Maintaining state:
# Even with Elixir not having any kind of OOP, it can store state (a.k.a.
# data) throught recursion -- pay attention in the listen() recursion call
# on the previous module.
defmodule Counter do
def new(start) do
spawn(Counter, :listen, [start])
end
def listen(counter) do
counter =
receive do
:count ->
counter + 1
:show ->
IO.puts(counter)
counter
end
listen(counter)
end
end
# User's API for that kind of module.
counter = Counter.new(0)
send(counter, :count)
send(counter, :count)
send(counter, :count)
send(counter, :show)
# Therefore:
# As you can see, this functions is the only ones required to achieve the
# behavior that we want. But how about get information from this sub
# processes? It's also possible using that same send/receive strategy.
defmodule Counter do
def new(start) do
spawn(Counter, :listen, [start])
end
def listen(counter) do
counter =
receive do
{:count, from, num} ->
send(from, {:ok, "Successfuly received new value."})
counter + num
{:get, from} ->
send(from, counter)
counter
end
listen(counter)
end
# Below, are the user's API function callbacks.
def count(pid, num) do
send(pid, {:count, self(), num})
receive do
{:ok, status} ->
{:ok, status}
end
end
def get(pid) do
send(pid, {:get, self()})
receive do
num ->
num
end
end
end
# User's API for that kind of module.
counter = Counter.new(0)
Counter.count(counter, 1)
Counter.count(counter, 0)
Counter.count(counter, 2)
Counter.get(counter)
# Finial notes:
# The asunc functions is just the user's API callbacks from the previous
# module, but without the receive action -- which means that those functions
# will execute and wont stop the run time waiting for a response.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment