Hi Francesco, thanks for sharing the example.

I agree that's a good structure for different sections of an app. I 
oversimplified the first example to show the current necessity of updater 
functions. The more painful part is deeply nested records such as in my 
last Geocode example. I feel it would be cumbersome creating layers of 
messages and OOP-style updaters to mimic the data structure. Either you end 
up with 50 messages in the model update or you end up with 50 files for 
each record that can be updated.

I'd love to see examples of how to achieve the following without lots of 
boilerplate.

    RcvGeocode geocode ->
        ( { model | user.profile.contact.address = extractAddress geocode 
}, Cmd.none )

On Sunday, March 5, 2017 at 4:09:08 PM UTC-5, Francesco Orsenigo wrote:
>
>
> Hi Martin, I wonder if for your case a different way to organise your code 
> would be viable:
>
> -- Family.elm
> updateFamily msg family =
>   case msg of
>     ChangeName newName -> ( { family | name = newName }, Cmd.none )
>     Save -> ( model, saveFamily family )
>
>
> selectedView family =
>     UI.form
>         [ UI.class "fluid"
>         , UI.onSubmit <| SaveFamily model.family
>         ]
>         [ UI.input
>             [ UI.label "Name"
>             , UI.value model.family.name
>             , UI.onInput ChangeName
>             ]
>         ]
>
>
> -- Update.elm
> update msg model =
>   case msg of
>     FamilyMsg familyMsg ->
>       let
>         (newFamily, familyCmd) = Family.update familyMsg model.family
>       in
>         ( { model | family = newFamily }, Cmd.map FamilyMsg familyCmd )
>
>
>
> This is how we organise the code in production and it scales really well; 
> it also has the advantage of removing as much logic as possible from the 
> view and keeping it in the update.
> The last block's boilerplate can be further reduced using an helper like 
> `mapBoth` from 
> http://package.elm-lang.org/packages/Fresheyeball/elm-return/latest (or 
> implementing it yourself, it's a couple of lines).
>
>
>
>
>
>
> On Monday, March 6, 2017 at 5:56:42 AM UTC+11, Martin Bailey wrote:
>>
>> Here are some real world examples of record updates that could be 
>> streamlined at the language level, including attempts to simplify UI code 
>> defining record updates.
>>
>> -- Update.elm
>> update : Msg -> Model -> ( Model, Cmd Msg )
>> update msg model =
>>     case msg of
>>         Update updater ->
>>             ( updater model, Cmd.none )
>>         SaveFamily family ->
>>             ( model, Cmd.saveFamily family )
>>         _ ->
>>             ( model, Cmd.none )
>>
>> -- View.elm
>> selected_family : Model -> UI.Node Msg
>> selected_family model =
>>     UI.form
>>         [ UI.class "fluid"
>>         , UI.onSubmit <| SaveFamily model.family
>>         ]
>>         [ UI.input
>>             [ UI.label "Name"
>>             , UI.value model.family.name
>>             , UI.onInput <| \val -> Update <| familyUpdater (\family -> { 
>> family | name = val })
>>             ]
>>         ]
>>
>> familyUpdater : (Family -> Family) -> Model -> Model
>> familyUpdater updater model =
>>     { model | family = updater model.family }
>>
>> -- familyUpdater looks simple enough, but at production scale with 
>> multiple embedded records, a few of these functions must be chained 
>> together to complete what could be a simple update such as 
>> model.family.contact.address.street = "Main Street"
>> -- Multiple specific Msg types such as UpdateFamily can be created to 
>> "clean" the view, but then it becomes really hard to achieve separation of 
>> concern as the Update function grows with out-of-context logic. Those 
>> updater functions are then moved to the Update file or you have to use many 
>> layers of let bindings. There are two concerns here, the update behavior 
>> being defined in the context of the form or becoming overly complex due to 
>> embedded records. The latter is more important.
>> -- Here's an example from another real world app :
>>
>>     RcvGeocode geocode ->
>>         let
>>             address =
>>                 extractAddress geocode
>>
>>             updated =
>>                 address |> updateAddress |> updateContact |> 
>> updateProfile |> updateUser model
>>         in
>>             ( { updated | geocode = geocode }, Cmd.none )
>>
>> -- This would look much nicer in my opinion :
>>
>>     RcvGeocode geocode ->
>>         ( { model | user.profile.contact.address = extractAddress geocode 
>> }, Cmd.none )
>>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to