It would be highly useful if there was a way to prevent view, subscription, 
or update from being called while also allowing for module transformation 
for TEA/following modules, which could all be handled via adding a single 
callback (described below) to Program (or a new version there-of).  It 
would require a simple change to the core javascript native code (linked 
below).  Just having Html.lazy on the top view itself is insufficient as it 
does not handle being able to prevent update calls (say if the model does 
not change and no command is raised, useful for view update, a rare case 
and could be ignored in general), being able to prevent or filter 
subscriptions (highly important in many cases, this would allow for ignore 
certain subscription messages, say you are handling input and do not want 
to listen to certain keys or only want to listen to certain keys then this 
would allow you to handle both filtering it as well as translating the the 
filtered data into a new message if wanted all in one step), as well as 
also preventing view updates on a variety of model updates (ways that lazy 
fails badly in is if you are receiving a stream of messages from a server, 
each one is causing a view update, when they are incoming as a singular 
stream and you know when it stops and can turn back 'on' rendering at that 
point, thus completely ignore the view updates for the given message stream 
Message and leave it on for everything else).  You could potentially nest 
lazy's only matching on specific criteria and a model variable to define 
whether it is on or not, but then you have to make sure you always turn it 
on on message types that handle views and turn it off only for your 
specific one, when that really should both be reversed in structure and 
should have no state variable.  Such a callback could also handle module 
transformation for TEA styled handling.

Thus for the new callback I propose is something like this, called `blah` 
for now since I am bad with naming and do not want to pre-dispose an idea 
of how it should work based on the name:
```elm

module main exposing (..)
main : Program ProgramFlagsmain =
    App.programWithFlags
        { init = init
        , blah = blah
        , view = view
        , update = update
        , subscriptions = subscriptions
        }
-- Snip other callback code as they are unchanged
blah : Msg -> ( Msg, States )blah msg =
  case msg of
    MyMessageThree _ -> ( msg, States.batch [ States.cancelView, 
States.cancelSubscriptions ) -- Just preventing certain callbacks
    MyMessageNine arg0 _ -> ( MyMessageThree arg0, States.all ) -- -- Just 
converting a message to another
    MyRedrawMessage -> ( msg, States.onlyView ) -- Just redraw the view, unsure 
if necessary but it is here for completion.
    MyMessageTwelve _ -> ( msg, States.onlyUpdate ) -- Just handle an update, 
subscriptions and view are not called
    OnKeyPress 13 -> ( msg, States.none ) -- Cancel every callback when 
OnKeyPress's value is 13, else it will fall back to the default lower of _ that 
passes through everything unchanged
    OnKeyPress 119 -> ( MoveUp, States.all) -- Convert this specific OnKeyPress 
into a MoveUp message instead, the OnKeyPress vanishes
    MaterialMessage msg -> Material.blah .mdl (\model newMdl -> { model | 
mdl=newMdl } ) msg
    _ -> ( msg, States.noChanges )

-- Material.blah could be implemented likemodule Material
blah : ( model -> Material.Model ) -> ( model -> Material.Model -> model ) -> 
Material.Msg -> ( Msg, States )blah getModel putModel msg =
  ( msg
  , States.delegate
    { getModel=getModel
    , putModel=putModel
    , update=Material.update
    , subscriptions=Material.subscriptions
    }
  )

```

As you can see it allows but is not restricted to:

   - Message translation
   - Callback cancellation
   - Message filtering
   - Message filtering and translation
   - TEA models direct update/subscriptions conversion (Just like how you 
   can do `.mdl model` to get `model.mdl`, I wish there were a way to do 
   something like `put .mdl model something` and it does `{ model | mdl = 
   something }`, it would make that last second callback more simple)
   - <salesman-voice>And more!

This solves a variety of issues in but not restricted to:

   - Simplifying the update to only handle what is actually important
   - Calling view at all only when it is needed (letting you not call it on 
   hot-path messages for example, like when getting a thousand messages to 
   fill in something but you don't want to render it until the stream is 
   complete)
   - TEA style inclusion of other modules in a central-include point 
   without needing to pepper crap like this all over your update and more:
   ```elm
   
               Helpers helpersMsg ->
                   let
                       ( helpersModel, helpersCmd ) =
                           helpers_update Helpers helpersMsg model.helpers
                   in
                       ( { model | helpers = helpersModel }
                       , helpersCmd
                       )
   
   ```




This is my prior post about this:

I do say that I wish there were some way to make some 'update' call as 
no-view and/or no-subscription re-call needed.  Like instead of returning 
`( model, Cmd.none )` we could do `( model, Cmd.cancelView )` or `( model, 
Cmd.cancelSubscription )` or both via `Cmd.batch`, or perhaps as a 
three-argument tuple that defaults to `( model, Cmd.none, StateChanges.none 
)` or so, which would default to calling everything.  I have a lot of 
update messages that are handled that do not change the view and/or 
subscriptions and it would be nice to prevent calling those somehow.  Hmm, 
actually a backward compatible change would be to add a new Program 
callback, in addition to the usual `init`, `update`, `subscriptions`, and 
`view`, add another one that I will call just `blah` for now, optional in 
the Program or so, but have it be like:
```
blah : Msg -> ( Msg, States )
blah msg ->
  case msg of
    MyMessageThree _ -> ( msg, States.batch [ States.cancelView, 
States.cancelSubscriptions )
    MyMessageNine arg0 _ -> ( MyMessageThree arg0, States.noChanges ) -- or 
`States.none`?
    MyRedrawMessage -> ( msg, States.cancelView )
    MyMessageTwelve _ -> ( msg, States.onlyUpdate )
    _ -> ( msg, States.noChanges )
```

And it would be called after `init` and before every call of `update`.  It 
would allow an easy way to translate one message type into another (maybe 
even a way to decorate it more so it can get passed to another modules 
update/subscription, this would be a **great** hooking location for 
modules), as well as a way to specify what states should be updated for a 
given message, a default no-op function could be supplied via 
`States.defaultHandle` or so that you could pass to the program so people 
do not have to override it in the easy cases.

Hmm, an idea for a module handler, one of the states could be something 
like:
```elm
    MaterialMessage msg -> ( msg, States.delegate { update=Material.update, 
subscriptions=Material.subscriptions } )
```
Which of course the other module could simplify via a helper to:
```elm
    MaterialMessage msg -> Material.blah msg
```

Looking at 
https://github.com/elm-lang/core/blob/4.0.4/src/Native/Platform.js shows 
that it would be easy to add that functionality to core.

So ideas about this style, issues, etc...?

-- 
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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to