Vertigo

Vertigo

Return type state different from expectation

I am working through “Functional Web Development with Elixir, OTP, and Phoenix” and came across a snippet that throws an exception. I might have made a typo somewhere or this might be due to a newer version of Erlang or Elixir since the book came out (didn’t have a chance to test this yet).

Page 78 indicates the state_data for the game object (GenServer) should look like this;

%{player1:.....etc....., state: :initialized}}

What I am getting is the following (using :sys.get_state);

[player1:......etc....., state: :initialized}]

My game module’s init function looks like this (seemingly identical to the book instruction)

  def init(name) do
    player1 = %{name: name, board: Board.new(), guesses: Guesses.new()}
    player2 = %{name: nil, board: Board.new(), guesses: Guesses.new()}
    {:ok, player1: player1, player2: player2, rules: %Rules{}}
  end

So I expected a Map but I got a List. Although I immediately noticed this I continued the next paragraph that tries to run handle_call when I invoke an ‘Game.add_player’ call (which tries to read attributes from the state_data) which obviously fails as it is a List not a Map;

iex(5)> Game.add_player(game, "Jeff")

20:34:28.960 [error] GenServer #PID<0.189.0> terminating
** (ArgumentError) argument error
    :erlang.apply([player1: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: "Frank"}, player2: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: nil}, rules: %IslandsEngine.Rules{player1: :islands_not_set, player2: :islands_not_set, state: :initialized}], :rules, [])
    (islands_engine) lib/game.ex:28: IslandsEngine.Game.handle_call/3
    (stdlib) gen_server.erl:661: :gen_server.try_handle_call/4
    (stdlib) gen_server.erl:690: :gen_server.handle_msg/6
    (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3
Last message (from #PID<0.182.0>): {:add_player, "Jeff"}
State: [player1: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: "Frank"}, player2: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: nil}, rules: %IslandsEngine.Rules{player1: :islands_not_set, player2: :islands_not_set, state: :initialized}]
Client #PID<0.182.0> is alive

    (stdlib) gen.erl:169: :gen.do_call/4
    (elixir) lib/gen_server.ex:921: GenServer.call/3
    (stdlib) erl_eval.erl:677: :erl_eval.do_apply/6
    (elixir) src/elixir.erl:265: :elixir.eval_forms/4
    (iex) lib/iex/evaluator.ex:249: IEx.Evaluator.handle_eval/5
    (iex) lib/iex/evaluator.ex:229: IEx.Evaluator.do_eval/3
    (iex) lib/iex/evaluator.ex:207: IEx.Evaluator.eval/3
    (iex) lib/iex/evaluator.ex:94: IEx.Evaluator.loop/1
** (EXIT from #PID<0.182.0>) shell process exited with reason: an exception was raised:
    ** (ArgumentError) argument error
        :erlang.apply([player1: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: "Frank"}, player2: %{board: %{}, guesses: %IslandsEngine.Guesses{hits: #MapSet<[]>, misses: #MapSet<[]>}, name: nil}, rules: %IslandsEngine.Rules{player1: :islands_not_set, player2: :islands_not_set, state: :initialized}], :rules, [])
        (islands_engine) lib/game.ex:28: IslandsEngine.Game.handle_call/3
        (stdlib) gen_server.erl:661: :gen_server.try_handle_call/4
        (stdlib) gen_server.erl:690: :gen_server.handle_msg/6
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Game.#28 seems to cause the problem, which looks like this;

def handle_call({:add_player, name}, _from, state_data) do
    with {:ok, rules} <- Rules.check(state_data.rules, :add_player)  # <- I don't think I am allowed to call rules on the state_data like this (although this is straight from the book)
    do
      state_data
      |> update_player2_name(name)
      |> update_rules(rules)
      |> reply_success(:ok)
    else
      :error -> {:reply, :error, state_data}
    end

Any takes?

First Post!

kokolegorille

kokolegorille

Which version of the book do You have? In mine, which is p1_0 I have on page 78…

def init(name) do
  player1 = %{name: name, board: Board.new(), guesses: Guesses.new()} 
  player2 = %{name: nil, board: Board.new(), guesses: Guesses.new()} 
  {:ok, %{player1: player1, player2: player2, rules: %Rules{}}}
end

It returns a map as expected.

BTW this is a Keyword List, which is a List of 2 elements tuples.

player1: player1, player2: player2, rules: %Rules{}

#is equal to

[{:player1, player1}, {:player2, player2}, {:rules, %Rules{}}]

Last Post!

Vertigo

Vertigo

Thanks for your reply! I’ll admit, this might be a typo after all, didn’t have a chance to check the book but I think my init function might be missing the Map accolades.

Where Next?

Popular in Questions Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? Ecto.Repo — Ecto v3.14.0 has exampl...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

Qqwy
Update: How to use the Blogs &amp; Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 130579 1222
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 40082 209
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New

We're in Beta

About us Mission Statement