Skip to content

Instantly share code, notes, and snippets.

@knewter
Last active August 18, 2016 02:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save knewter/d62f3dd4889f798d28f2e80fdb8e5256 to your computer and use it in GitHub Desktop.
Save knewter/d62f3dd4889f798d28f2e80fdb8e5256 to your computer and use it in GitHub Desktop.
A discussion around an idea for separating the bits of `update` internally

A discussion around an idea for separating the bits of update internally

NOTE: I really just want to have a discussion around this, see if someone's tried it, what dumb things I'm ignoring, etc.

Premise

update is Msg -> Model -> (Model, Cmd Msg). Very often (I think every time I've ever done anything?) I will end up with things that "update the model" based on new Msg (I am enjoying thinking of these as strictly events in the EventSourcing/WAL sense), and then either some Cmd Msg or none. Every time I can remember, my Cmd Msg bit needed the newModel which often lends itself to my having let wrappers that I don't love th elook of.

I'm considering that all of my update branches might eventually want to separate the model updating (new facts came in) from the side effects being demanded as a result:

module Foo exposing (..)

import Dict exposing (Dict)


type alias Model =
    { things : Dict Int Bool }


type Msg
    = ToggleThing Int


threadUpdate : a -> (a -> b) -> ( a, b )
threadUpdate m f =
    ( m, f m )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg oldModel =
    threadUpdate (apply msg oldModel) (demand msg)


apply : Msg -> Model -> Model
apply msg model =
    case msg of
        ToggleThing thingId ->
            { model | things = Dict.update thingId (Maybe.map not) model.things }


demand : Msg -> Model -> Cmd Msg
demand msg newModel =
    case msg of
        ToggleThing thingId ->
            -- this returns the Cmd for doing that bit, whatever
            tellServerToggled thingId newModel


tellServerToggled : Int -> Model -> Cmd Msg
tellServerToggled thingId model =
    -- imagine real stuff
    Cmd.none

My thoughts

Cons

More verbose, less convenient

My immediate realization is that this is actually a lot more verbose, and my whole point was to reduce verbosity. Also, I can't have access to oldModel in the demand portion (easy enough to have it take a 2-tuple of (oldModel, newModel) and have apply return that).

Pros

Strict separation of 'do stuff' with 'stuff happened'

This part I like a lot. It's nice to only think about one side of the 2-tuple we have to return at a time.

Summary

I don't know. I just wanted to write it out and think about it. Anyone want to take this and add pros/cons, mention the time they tried it and it (sucked/was awesome), mock me, etc?

@john-kelly
Copy link

john-kelly commented Aug 17, 2016

would you ever change the newModel in the demand?

if not, maybe you ONLY want to return the Cmd Msg

@knewter
Copy link
Author

knewter commented Aug 17, 2016

No. The whole 'apply this fact to the model' is a result of an incoming message. I have the updated model. A demand is just 'what do I do with the outside world now?' and can't get any data back until the Cmd results in a Msg anyway, so there's zero chance I would ever do that. (I've never run into a situation where that makes sense at least)

This is also encoded in the type of demand. It just...can't. and I never want it to.

@knewter
Copy link
Author

knewter commented Aug 17, 2016

I don't know what I was thinking there...john-kelly pointed out that last sentence is a lie. Oops :) In that case I think its return type is actually kind of bad.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment