No with clause matching when using case

I’ve cleaned the IO.puts out of the pasted code.

def next_phase(state, player, opponent) do
    current = state["status"]["phase"]
    ind = Enum.find_index(turn_sequence(), fn(x) -> x == current end)
    next = Enum.at(turn_sequence(), Enum.at(turn_sequence_indexes(), ind))
    state =
      case state["status"]["player_turn"] == player do
        true ->
          case state[opponent]["stops_opponent"][current] do
            true ->
              # this is where the error is happening, inside this clause, the last IO.puts is actually here instead of this comment
              state
              |> put_in([player, "on_play"], false)
              |> put_in([opponent, "on_play"], true)
              |> set_stack_passing(player, opponent, current, next)
              |> set_timers(player, opponent)
              |> prepare_broadcast("passing")
            false ->
              state
              |> put_in(["status", "phase"], next)
              |> refresh_current_timer(player)
              |> prepare_broadcast("pass-enter")
              case state[player]["stops_self"][next] do
                true ->
                  {:ok}
                false ->
                  state
                  |> pass(player, state[player]["id"])
              end
          end
        false ->
          state
          |> put_in([player, "on_play"], false)
          |> put_in([opponent, "on_play"], true)
          |> put_in(["status", "phase"], next)
          |> set_timers(player, opponent)
          case state[opponent]["stops_self"][next] do
            true ->
              state
              |> prepare_broadcast("enters")
            false ->
              state
              |> pass(opponent, state[opponent]["id"])
          end
      end
  end

So if I have the IO.puts statements to see the chain, I get this on the console:

inside pass
inside active_player
23
true
false
inside active_player true
inside pass_stack
nil
inside nil pass stack
#these are the logs referring to that method
inside true player_turn main
player_1
inside true player_turn, true opponent stops current

Then it crashes with:

[error] GenServer #PID<0.999.0> terminating
** (WithClauseError) no with clause matching: %{"game_id" => 5, "messages" => ["mofo is passing to the main phase"], "player_1" .... I've truncated this, but it's basically the game state

I thought it might have something to do with the state= assignment, but I’ve removed it and it throws the same error. I can see that the piping goes to prepare_broadcast() because a message is added to the “messages” key.
Can anybody see something wrong with my case...do ? Thanks

Assigning a result of the top-level case to state local variable does not make any sense in the first place since it immediately gets discarded.

The line number where the error occurs would help,

1 Like

I was not going to write it but you explicitly asked. Yes, there’s plenty of wrong with your code. You have got 3 layers of nested case statement in it, with multiple branches. Split it up to smaller functions, this looks like a nightmare to work with.

You need to show us more error messages and/or state to be able to help you.

2 Likes

@mudasobwa The problem is it doesn’t give me a line error - It just throws that exception and indeed I didn’t assign state to the case before, but that doesn’t solve it, either way?

@hubertlepicki - Indeed, but I usually refactor after I have the structure working - I will try refactoring to see if it throws me a line where the error is occurring.

But the structure is actually simple, in pseudo code it would be:

is the player passing in its own turn?
-> true
 does the opponent want to stop in this phase?
   -> true
     #errors
     pass priority to opponent yabdadaba
  -> false
    keep priority on the current player and pass to next phase
-false
  #meaning the current passing player is not on his turn, and accepts to pass to the next phase
  does the opponent (who's in the current turn) stop on his own next phase?
  -> true
    set priority to him, move to next phase
  - > false
    recur this call to find next phase where the current turn player will stop

Comment each transformation you currently do. Uncomment them step by step until the error occurs again. Step into that transforming function you discovered to be the culprit and show us the code of it.

1 Like

I’m sorry for having wasted your time guys, the error was happening not in this function but on one way above the call stack - that dealt with the response from this one, which should have been obvious by the error itself since I wasn’t using with here. Thanks for looking at it though.

One more question, is there any reason why it didn’t give me a line where the error occurs? Is it because it’s inside a with argument match?

No, that’s odd, if you have a complete reproducible git that we can clone and immediately test then it would be good to see and potentially report an issue. :slight_smile:

Yes, I believe it’s a bug because it had happened before actually, a with clause not showing the line error. Should I file a bug report?

I don’t have it online yet, I can put it like tomorrow or something. I had this written all in rails, with active-cable and jquery, but wasn’t yet finished so I decided to re-write what I had in elixir and complete the game - and changed the front-end to vuejs as well - overall it feels less snappier than with ruby/jquery (I guess it’s actually due to vue) - although much more organised from the point of view of code. I have perhaps 2 weeks of elixir under my belt, so you have to promise to not make fun of the code :smiley: , I welcome comments on the code structure though (most of it will be refactored and extracted when the time comes nonetheless).

I also thought about learnig elm to use instead of vue, but then it seemed like learning elixir was enough for now.

Once you get it down to a minimal reproduceable example with a project you just mix test on or so, yep. :slight_smile:

with has some generated code and I’m guessing the meta information is not being carried around to potential clausematching sites.

1 Like

So I went to https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1
Then to the source code and it’s a single line defmacro with(args), do: error!([args]) along with the documentation, which explains the macro, but where is this with macro itself defined?

Since its a special form it’s behaviour is specified in the compiler. You’ll need to dig into the erlang sources. Since I’m on mobile I cant even point you into a rough direction…

2 Likes

I think it is here: https://github.com/elixir-lang/elixir/blob/master/lib/elixir/src/elixir_clauses.erl#L131

1 Like

Thanks, I shouldn’t have asked, I feel dumb after reading through it… :wink:
I’ll try to digest it in the meanwhile