Search code examples
elixirelixir-iex

IEX stalling after spawning process that waits to receive messages


I'm completely new to Elixir but had to use Erlang for a piece of coursework and I am currently trying to line by line translate it to Elixir.

I have it compiling successfully and everything seems good to go. I want to start a server process using the start_server() function, which spawns a server on a new process and then send it a message from iex:

  def server(s, us, sums, n) do
    IO.puts("Server online")
    receive do
      :finished ->
        :ok
        %... More message patterns 
        end
    end
  end

  def start_server() do
    server_pid = spawn(server(0, 0, [], 0))
    Process.register(server_pid,:server)
    IO.puts("server started and registered. Should be waiting for message")
  end

However, when running start_server in iex, it seems to be stuck waiting for a message, not allowing me to send any more commmands, unlike what I'm used to in Eshell. I looked online for simple examples of this same scenario (spawning a process that is waiting for messages) and found this "Salutator" example, but following it's instructions lead to the same issue. Is there something simple that I am missing?


Solution

  • When using spawn, you need to pass it a function to run, like one of these two:

    spawn(fn -> IO.puts("hi from pid #{inspect(self())}")
    spawn(&MyModule.print_my_pid/0)
    

    What you're doing is the equivalent of this:

    IO.inspect(self())
    spawn(IO.inspect(self()))
    # This code prints:
    #PID<0.108.0>
    #PID<0.108.0>
    ** (ArgumentError) errors were found at the given arguments:
    
      * 1st argument: not a fun
    
        :erlang.spawn(#PID<0.108.0>)
        iex:6: (file)
    

    As you can see, both the self() calls had the same PID - they both ran on the parent process. Then, spawn was called with the output of that, which is not a function and thus invalid.

    What you want here is probably to wrap the server call in an anonymous function:

    server_pid = spawn(fn -> server(0, 0, [], 0) end)