I did the ping-pong exercise from the OTP guide book and I don’t understand the function of spawn/1 function.
Here is the code
lib/pingpong.ex
defmodule PingPong do
def start do
pong_pid = spawn(Pong.loop)
ping_pid = spawn(Ping, :ping, [pong_pid])
end
end
lib/pong.ex
defmodule Pong do
def loop do
IO.puts "running"
receive do
{sender_pid , :ping} ->
:timer.sleep(1_000)
IO.puts "pong"
send(sender_pid, {self, :pong})
end
IO.puts "ran"
loop
end
end
Now, when I did iex> PingPong.start it just printed “running” and just stood there. If I change the line 3 in PingPong to
# spawn/3
pong_pid = spawn(Pong, :loop, [])
it works. So spawn/1 just spawns the function. But what value does it have when it blocks the current process until the function has finished?
You’re misunderstanding a bit about what’s going on. spawn/1 is supposed to take an anonymous function IE:
spawn(fn -> Pong.loop end)
or just spawn(&Pong.loop/0)
You’re calling the function Pong.loop and then passing its result to spawn. However, Pong.loop just goes in an infinite loop, so your program sits waiting forever.
Thanks. I tried as you wrote and indeed it works. But this brings another question.
Every function should return something. The way I understand it the anonymous function calls Pong.loop/0. Since Pong.loop/0 is the last declaration in the anonymous function then it’s return value is essentially the anonymous function’s return value. Why isn’t it the same as calling directly the Pong.loop/0?
I’m not sure what you’re saying. It sounds like you’re saying fn -> x() end is just equivalent to x. The difference is that if I do
y = x()
Then x() is called immediately, and y has the value of whatever x returns. If x is an infinite loop, the program never terminates.
However if I have
z = fn -> x() end
x() has not yet been called. It will only be called when the function that wraps it has been called, IE: z.(). z’s value is a function itself, not the result of the function. This means that if you pass z to spawn, spawn can start a new process and THEN call z.() in that new process. Calling z.() will evaluate the contents of the anonymous function from earlier, and then that’s when x() is called.