# How do you organize \`update\` with custom type Models?

**URL:** <https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024>\
**Category:** Learn\
**Created:** [July 18, 2019, 10:01pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024 "2019-07-18T22:01:40Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Janiczek](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/janiczek/32/4516_2.png) [@Janiczek](https://discourse.elm-lang.org/u/Janiczek)\
**Post date:** [July 18, 2019, 10:01pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/1 "2019-07-18T22:01:40Z")

</div>

Hello everybody!  
Let’s say I have this Model and Msg:

```elm
type Model
  = LoggedOut
  | LoggedIn
  | Synced {...}
  | Error String

type Msg
  = GotLoggedIn
  | GotMainPage {...}

```

How do you write the `update` function in this case?  
I see a few options: (note that for the sake of brevity I don’t extract inner functions into top-level definitions, even though that’s what I’d normally do)

## 1. Group by Model, then by Msg

```elm
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case model of
    LoggedOut ->
      case msg of
        GotLoggedIn -> ...
        GotMainPage _ -> ...

    LoggedIn ->
      case msg of
        GotLoggedIn -> ...
        GotMainPage _ -> ...

    Synced _ ->
      case msg of
        GotLoggedIn -> ...
        GotMainPage _ -> ...

    Error _ ->
      case msg of
        GotLoggedIn -> ...
        GotMainPage _ -> ...

```

## 2. Group by Msg, then by Model

```elm
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GotLoggedIn ->
      case model of
        LoggedOut -> ...
        LoggedIn -> ...
        Synced _ -> ...
        Error _ -> ...

    GotMainPage _ ->
      case model of
        LoggedOut -> ...
        LoggedIn -> ...
        Synced _ -> ...
        Error _ -> ...

```

## 3. Only handle what makes sense, wildcard the rest

(notably used by [elm-spa-example](https://github.com/rtfeldman/elm-spa-example/blob/master/src/Main.elm#L208-L277))

```elm
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case (msg, model) of
    (GotLoggedIn, LoggedOut) -> ...
    (GotMainPage _, LoggedIn) -> ...
    (GotMainPage _, Synced _) -> ...
    _ -> ...

```

The last one seems like it leads to least amount of boilerplate, but I fear the wildcard would throw out the ability to find out what’s happening and to debug the program fast. The variants without wildcard make you at least think about each possibility before writing a new `-> noop` case in each.

What do(/would) you do? Maybe some hybrid - 1 or 2 with wildcards?

---

<div class="post-metadata">

**Author:** ![Chadtech](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chadtech/32/609_2.png) [@Chadtech](https://discourse.elm-lang.org/u/Chadtech)\
**Post date:** [July 18, 2019, 10:40pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/2 "2019-07-18T22:40:55Z")

</div>

I would choose option 1

---

<div class="post-metadata">

**Author:** ![akoppela](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/akoppela/32/250_2.png) [@akoppela](https://discourse.elm-lang.org/u/akoppela)\
**Post date:** [July 19, 2019, 1:12am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/3 "2019-07-19T01:12:02Z")

</div>

Am I correct that `LoggedOut` model could get only `GotLoggedIn`, `LoggedIn` and `Synced` models could get only `GotMainPage`, and `Error` should get no messages? And am I correct that `Synced` is logged in with main page, and `Error` is logged in without main page?

---

<div class="post-metadata">

**Author:** ![Lucas\_Payr](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/lucas_payr/32/4993_2.png) [@Lucas\_Payr](https://discourse.elm-lang.org/u/Lucas_Payr)\
**Post date:** [July 19, 2019, 4:29am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/4 "2019-07-19T04:29:53Z")

</div>

I’d use 3.

As long as all messages can actually occur for all states of the Model, I would only use wildcards for the Msg not the Model.

Once there are actually a lot of Msgs that only work for a specific state I would start giving every state its own Msg type and extract it to its own update function. In that case I would use a wildcard for both Msg and Model.

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 19, 2019, 5:42am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/5 "2019-07-19T05:42:37Z")

</div>

small note:  
[Version 2 with wildcards](https://github.com/elm/package.elm-lang.org/blob/master/src/frontend/Main.elm#L118-L157) is the chosen method for [package.elm-lang.org](http://package.elm-lang.org).

---

<div class="post-metadata">

**Author:** ![Janiczek](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/janiczek/32/4516_2.png) [@Janiczek](https://discourse.elm-lang.org/u/Janiczek)\
**Post date:** [July 19, 2019, 7:15am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/6 "2019-07-19T07:15:45Z")

</div>

The particulars of this example shouldn’t matter, and eg. Error could be transitioned to from any other Model, but let’s say yes. Does your preferred strategy change with the shape of the FSM?

---

<div class="post-metadata">

**Author:** ![Janiczek](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/janiczek/32/4516_2.png) [@Janiczek](https://discourse.elm-lang.org/u/Janiczek)\
**Post date:** [July 19, 2019, 7:16am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/7 "2019-07-19T07:16:38Z")

</div>

Hmm, so there are some global Msgs and then some Msgs specific to the Model/Page cases

---

<div class="post-metadata">

**Author:** ![akoppela](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/akoppela/32/250_2.png) [@akoppela](https://discourse.elm-lang.org/u/akoppela)\
**Post date:** [July 19, 2019, 7:37am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/8 "2019-07-19T07:37:48Z")

</div>

I would go with second option. Because `Msg` is the language update function speaks. And I would create helper functions to check if user is logged or not.

```auto
isLoggedOut : Model -> Bool
isLoggedOut model =
  LoggedOut -> True
  LoggedIn -> False
  Synced _ -> False
  Error _ -> False

isLoggedIn : Model -> Bool
isLoggedIn =
  not isLoggedOut

update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    GotLoggedIn ->
      if isLoggedOut model then
        — Process changes, because only logged out user can log in
      else
        ( model, Cmd.none)

    GotMainPage _ ->
      if isLoggedIn model then
        — Process changes, because only logged in user can get main page
      else
        ( model, Cmd.none)

```

Implementation maybe different if a message should be processed differently for different model states (e.g. update process for `GotMainPage` is different for different model states)

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [July 19, 2019, 10:00am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/9 "2019-07-19T10:00:44Z")

</div>

In practice I seem to most often do 3…

Note that 1 and 2 won’t remove the need to do wildcards. If you have states which cannot process some messages, you just end up with wildcards beneath each of those states.

So long as you design so that the wildcard is always a no-op, I don’t feel it is such a problem to lose exhaustiveness checking.

For 1, 2:

```
_ -> (model, Cmd.none)

```

or for 3:

```
(_, _) -> (model, Cmd.none)
```

---

<div class="post-metadata">

**Author:** ![pdamoc](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/pdamoc/32/36_2.png) [@pdamoc](https://discourse.elm-lang.org/u/pdamoc)\
**Post date:** [July 19, 2019, 10:49am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/10 "2019-07-19T10:49:05Z")

</div>

> [@rupert](#):
>
> I don’t feel it is such a problem to lose exhaustiveness checking.

With (2) you get exhaustiveness checking for messages which is, in my opinion better than exhaustiveness for model (1) .

---

<div class="post-metadata">

**Author:** ![Chadtech](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/chadtech/32/609_2.png) [@Chadtech](https://discourse.elm-lang.org/u/Chadtech)\
**Post date:** [July 19, 2019, 10:53am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/11 "2019-07-19T10:53:29Z")

</div>

Yeah, in my mind (and I’m sure many of all your minds too) the `Msg` represents something that happens. So having one big `Msg` type for all types of pages or stages (`LoggingIn`, `LoggedIn`, …) is strange and implausible because its like saying “Anything can happen at any time”, even tho its implicit that different pages and stages have different UIs and different behavior.

So if theres some set of “things that can happen” which are clearly limited to particular chunks of your application, I would make a `Msg` type for that chunk of the application. There are things that truly do happen across all pages / stages of your application, so those _should_ go in the top level `Msg`, but those are the minority case, not that majority case.

(_All of this within whats practical and reasonable. When it comes to `Msg` you always have to handle weird cases, and also those weird cases always end up being more possible than it appears._)

---

<div class="post-metadata">

**Author:** ![ymtszw](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/ymtszw/32/2360_2.png) [@ymtszw](https://discourse.elm-lang.org/u/ymtszw)\
**Post date:** [July 19, 2019, 11:07am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/12 "2019-07-19T11:07:11Z")

</div>

> [@pdamoc](#):
>
> > I don’t feel it is such a problem to lose exhaustiveness checking.
> 
> With (2) you get exhaustiveness checking for messages which is, in my opinion better than exhaustiveness for model (1) .

My feeling is this, too. I do this sometimes:

```elm
update msg model =
    case msg of
        DoThis ->
            case model of
                WhenItIsA data ->
                    doThis data

                _ ->
                    pure model
        DoThat ->
            case model of
                WhenItIsB data ->
                    doThat data

                _ ->
                    pure model

```

Point is extracting actual update into private functions (or, use sub-components’ `update` functions and wire results into root model with private functions. Like [this](https://github.com/elm/package.elm-lang.org/blob/master/src/frontend/Main.elm#L139-L157) in package site), and keep root `update` looks simple.  
`update` is, IMO, kind of “router” of application logic, and keep “router” looks simple is important for readability.

---

<div class="post-metadata">

**Author:** ![popara](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/popara/32/719_2.png) [@popara](https://discourse.elm-lang.org/u/popara)\
**Post date:** [July 19, 2019, 2:23pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/13 "2019-07-19T14:23:19Z")

</div>

First, this is strictly cultural question, how team want to work consistently. I guess there is no One Right Way in this case. My gut says that you should match against model first, because, you are modifying it, and you know that in some cases some of stray events just don’t make sense. Hence I would go with 1.

But one also can argue that modeling both of messages and model is off, because (kough\*) you are representing impossible combinations of events and states.

Now solution to it is knowing exact nature of interaction. I would carry more information in the messages.  
From I can tell there are two kind of events (messages), the one that have the User and one that don’t:

I will free ball just to illustrate the point:

```auto
type Model 
  = A 
  | B SomeData 
  | C Error

type Msg 
   = SetC Error
    | MoveToB SomeData 
    | SimpleA 

update msg model =
   case msg of
     SetC error -> C error
     MoveToB data -> B data
     SimpleA -> A 

```

which brings me to the point, maybe if you are modeling FSM, role of messages is not to describe what happened but how FSM should transition, and logic about which transition you should perform should be in message generating function, ie `view`. Helpful thing here would be use of Json Decoders because you can mute event with `Json.fail` if you think there is no point of updating.

```auto
view model = 
 case model of 
  A -> div [] 
    [button [ onClick <| SetC (NastyError)] [text "Make error"] 
   , input [onInput (toSomeData >> MoveToB) [] 
   ] 
  B data -> Debug.todo " : D " 

```

---

<div class="post-metadata">

**Author:** ![rupert](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/rupert/32/1775_2.png) [@rupert](https://discourse.elm-lang.org/u/rupert)\
**Post date:** [July 19, 2019, 2:31pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/14 "2019-07-19T14:31:59Z")

</div>

> [@popara](#):
>
> But one also can argue that modeling both of messages and model is off, because (kough\*) you are representing impossible combinations of events and states.

Do to the asynchronous nature of event processing in Javascript and Elm, the possibility of non-determinism is always there.

For example, suppose you have an info pop-up dialog box that fetches some information from the server. This dialog also has a ‘Dismiss’ button on it that the user can hit once they have seen it and are ready to move on. Now suppose that the server call is taking too long, so the user gets bored and hits the button before the info is loaded. After this, the data does arrive from the server and triggers a `DataLoaded` event, but the application is now not in the correct state that it can show this information. The best course of action is probably just to ignore it.

So the correct model for an elm application is not an FSM, but a non-deterministic FSM. By which I mean an FSM which corrales a non-deterministic event stream into well-behaved sequence of state transitions.

This is also why the logic cannot be in the view function - because the view is only updated on the animation frame. It can lag behind the state machine, and end up creating transations that use stale state.

Here is the Ellie I wrote to illustrate how stale state can happen: [https://ellie-app.com/yVC9wPk33xa1](https://ellie-app.com/yVC9wPk33xa1)

---

<div class="post-metadata">

**Author:** ![popara](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/popara/32/719_2.png) [@popara](https://discourse.elm-lang.org/u/popara)\
**Post date:** [July 19, 2019, 3:11pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/15 "2019-07-19T15:11:01Z")

</div>

> [@rupert](#):
>
> This is also why the logic cannot be in the view function - because the view is only updated on the animation frame. It can lag behind the state machine, and end up creating transations that use stale state.

I understand totally the case and you are right, sometimes you have to eat those impossible messages. 🙂

---

<div class="post-metadata">

**Author:** ![avh4](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/avh4/32/97_2.png) [@avh4](https://discourse.elm-lang.org/u/avh4)\
**Post date:** [July 19, 2019, 4:31pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/16 "2019-07-19T16:31:50Z")

</div>

I used to ask myself this a lot, but over time I’ve found that most places where I originally thought to have the Model be a union type ended up being better by refactoring the Model to be a record instead.

For instance, instead of having

```elm
type Model
    = LoggedOut
    | Authorizing AuthToken
    | LoggedIn User
    | DataLoaded User Data

```

I think it turns out better to have

```elm
type alias Model =
    { auth : Auth
    , data : Maybe Data
    }

type Auth
    = LoggedOut
    | GotToken AuthToken
    | LoggedIn User

```

This avoids the issue of having to destructure both model and msg… (or maybe you could argue this is a form of destructuring the Msg first, since some messages would still need to destructure fields of the Model).

I think this also makes the code more robust to refactoring because the handling of each message is only coupled to the fields of the model that are relevant to processing that message, and there’s no page-wide states that all messages are forced to understand.

---

<div class="post-metadata">

**Author:** ![neurodynamic](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/neurodynamic/32/984_2.png) [@neurodynamic](https://discourse.elm-lang.org/u/neurodynamic)\
**Post date:** [July 19, 2019, 5:55pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/17 "2019-07-19T17:55:59Z")

</div>

> [@popara](#):
>
> Now solution to it is knowing exact nature of interaction. I would carry more information in the messages.

This has been a big part of my strategy for this situation. It feels better aligned with keeping impossible states impossible, as you said, because you can necessarily only pass that message when all that data is available to pass with it.

Sometimes it seems like it ends up with me having biiig messages in terms of how many args/how much data is in them. Maybe that just means I should be using more records or similar for message arguments or something, though. Haven’t worked out all the kinks yet.

---

<div class="post-metadata">

**Author:** ![neurodynamic](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/neurodynamic/32/984_2.png) [@neurodynamic](https://discourse.elm-lang.org/u/neurodynamic)\
**Post date:** [July 19, 2019, 7:24pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/18 "2019-07-19T19:24:20Z")

</div>

While I’m thinking about it, [here’s an example of me making this kind of change](https://gitlab.com/neurodynamic/body_scan_elm/commit/bf008ba56498f1d7bd69e372a53e994c1f035030).

---

<div class="post-metadata">

**Author:** ![Bojan\_Ristic](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/bojan_ristic/32/2379_2.png) [@Bojan\_Ristic](https://discourse.elm-lang.org/u/Bojan_Ristic)\
**Post date:** [July 24, 2019, 8:39am UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/19 "2019-07-24T08:39:30Z")

</div>

IMHO it really depends on the app at hand. In most cases I take the `(2)` approach, but in some cases I use `(3)`.

But I also make extensive use of helper functions to `map` function over certain states.

Here is example of the app state with tabbed interface:

```auto
type Model 
    = ProductsTab ProductsTabData
    | ProductsTabSubmitting ProductsTabData
    | UsersTab UsersTabData
    | UsersTabSubmitting UsersTabData

```

As illustrated in this example application can be in different states while holding the same data.

When working with model like this I create helper functions:

```auto
mapProductsData : (ProductsTabData -> ProductsTabData) -> Model -> Model

mapUsersData : (UsersTabData -> UsersTabData) -> Model -> Model

```

---

<div class="post-metadata">

**Author:** ![madasebrof](https://yyz1.discourse-cdn.com/flex035/user_avatar/discourse.elm-lang.org/madasebrof/32/363_2.png) [@madasebrof](https://discourse.elm-lang.org/u/madasebrof)\
**Post date:** [July 24, 2019, 12:59pm UTC](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024/20 "2019-07-24T12:59:54Z")

</div>

Obviously, lots of opinions, but for SURE I would do #2, and also convert the `Model` to a `record` / `type alias` instead of a `custom type`, e.g.

```auto
type alias Model = 
  { userLogin : LoginStatus
  , synced : SyncRecord 
  , maybeError : Maybe String
  }

```

The basic idea is that the Elm event loop takes a `message` and a `model` as input, updates a portion of the `model` based on the `message`, then returns a modified `model` and a possible `command` (or `command` list) as output, e.g.

```auto
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
  case msg of
    UpdateLogin newLoginState ->
        ( { model | userLogin = newLoginState }, Cmd.none )

etc...

```

Also, I’d avoid wildcards.

At least, that’s how we do it. (Large production codebase)

[Next page](https://discourse.elm-lang.org/t/how-do-you-organize-update-with-custom-type-models/4024.md?page=2)
