How to decode strings to custom type?

Hi

I am learning elm and need some guidance around decoding and types?

I’m creating a little multiplayer game that uses web sockets. When one player makes a move, the new game state is broadcast to all players. The game has a variety of round types like “normal_round”, “power_play_round”, “sudden_death_round”. I am currently decoding this as a String and doing lots of comparisons based on this e.g.

case model.round of 
    "normal_round" -> ...
    "power_play_round" -> ...

I feel this is somewhat incorrect/bad pattern, like magic strings.

Would a better approach be a custom type? Something like:

type GameRound = Normal | PowerPlay | SuddenDeath

type alias Model = {
    round : Maybe GameRound
    ...
}

My concern here is that I don’t really know what the Nothing means in this case.

Keep strings or custom type? Any guidance is most welcome.

Hi Sharkey,

From what I can make out, it would be cleaner to use a custom type than strings.

If your game will always be in a state of some kind of Round then why not have

type alias Model = {
round : GameRound

}

Why would you want Maybe Round? Even, if there can be a state when no round is active you could have your custom type as

type GameRound = NoRound | Normal | PowerPlay | SuddenDeath

That way Maybe Round won’t be required.

HTH

Vani

Do you send JSON over the WebSocket?

If you get something like this:

{
    "round": "normal_round"
}

Then you could create a JSON decoder like this:

type GameRound
    = Normal
    | PowerPlay
    | SuddenDeath


gameRoundDecoder : Json.Decode.Decoder GameRound
gameRoundDecoder =
    Json.Decode.string
        |> Json.Decode.andThen
            (\round ->
                case round of
                    "normal_round" ->
                        Json.Decode.succeed Normal

                    "power_play_round" ->
                        Json.Decode.succeed PowerPlay

                    "power_play_round" ->
                        Json.Decode.succeed SuddenDeath

                    _ ->
                        Json.Decode.fail ("Unknown round type: " ++ round)
            )


type alias Model =
    { round : GameRound
    , error : Maybe Json.Decode.Error
    }


update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        GotWebSocketMessage json ->
            case
                Json.Decode.decodeValue
                    (Json.Decode.field "round" gameRoundDecoder)
                    json
            of
                Ok gameRound ->
                    ( { model | round = gameRound }, Cmd.none )

                Err error ->
                    ( { model | error = Just error }, Cmd.none )

And in your view, you could display that model.error if you want (in case you ever receive something bad on the WebSocket).

1 Like

This helped, thank you

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.