Search code examples
design-patternsfunctional-programmingreactive-programmingmessageelm

What is the translator pattern in elm?


In the elm git book an architecture is described wherein child components generate messages which are disseminated via the main update function, eventually being handled by the appropriate update function in a child component. How does the translator pattern differ from this and what are the use cases of each pattern. Please provide a simple example.


Solution

  • Whenever you have a nested "component" with an update function, you will need to make sure the parent passes through the child Msgs and Cmds. The git book outlines this with a simple example (where this code is in the parent, and Widget is the child):

    type Msg
      = WidgetMsg Widget.Msg
    
    update message model =
      case message of
        WidgetMsg subMsg ->
          let
            ( updatedWidgetModel, widgetCmd ) =
              Widget.update subMsg model.widgetModel
          in
            ( { model | widgetModel = updatedWidgetModel }, Cmd.map WidgetMsg widgetCmd )
    

    The above will be necessary any time a child has an update function. However, the in the above example, the parent never knows or cares what child messages are being communicated to the child.

    But now, consider the case that a parent needs to know about a Msg generated by a child. For instance: a game where a nested child component needs to communicate with a parent that the game is lost.

    The Translator Pattern is useful when a parent component needs to react to a message returned from the child update function. Here is the basic structure of the update function in the linked example:

    GameMsg internalMsg -> 
      let
        (game_, cmd) 
           = Game.update internalMsg model.game
      in
        { model | game = game_ } ! [ Cmd.map gameTranslator cmd ]
    

    Notice that it looks a lot like the earlier update example; the main difference is that rather than mapping the Cmd directly to a blind parent Msg (blind in that the single WidgetMsg of the first example only passed around the child Msg), the gameTranslator mapping function allows you to map to one of the parent messages.

    It may be helpful to read the Translator Pattern Blog Post in its entirety. It was written for Elm 0.17 so there are a few syntax changes, but the general idea still holds.