Skip to content

Changes in subscriptions without effect if model changes in response to command from init #1776

@JaSpa

Description

@JaSpa

This is a problem with elm 0.19.0.

SSCCE

import Browser
import Html exposing (Html)
import Task
import Time exposing (Posix, Zone)

type Model
    = Loading
    | HasZone Zone

type Msg
    = NewZone Zone
    | Tick Posix

main =
    Browser.element
        { init = init
        , update = update
        , subscriptions = subscriptions
        , view = view
        }

init : () -> ( Model, Cmd Msg )
init _ =
    ( Loading, Task.perform NewZone Time.here )

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case Debug.log "update in response to" msg of
        NewZone zone ->
            ( HasZone zone, Cmd.none )
        Tick _ ->
            ( model, Cmd.none )

subscriptions : Model -> Sub Msg
subscriptions model =
    case Debug.log "subscriptions for" model of
        Loading ->
            Sub.none
        HasZone _ ->
            Time.every 1000 Tick

view : Model -> Html Msg
view model =
    Debug.log "view for" model
        |> always (Html.text "Nothing to see here, please look at the console.")

Ellie by @adeschamps showing the same problem: https://ellie-app.com/38yPbFdvv6qa1

Expected behaviour

In the browser's console the messages from Debug.log should appear in this order:

  1. view for Loading
  2. subscriptions for Loading
  3. update in response to NewZone
  4. subscriptions for HasZone
  5. view for HasZone
  6. update for Tick
  7. subscriptions for Tick
  8. view for Tick

with the last three steps repeated every second.

Actual behaviour

In the browser's console the following messages appear:

  1. view for Loading
  2. subscriptions for Loading
  3. update in response to NewZone
  4. subscriptions for HasZone
  5. view for HasZone

Analysis

  • Core problem: older subscriptions overwrite newer subscriptions.
  • Happens if: the command returned from the init function alters the model in such a way that the subscriptions change.
  • Guess on the problem location: _Platform_dispatchEffects. In the for-in loop is no ordering between subscriptions and commands.

More detailed breakdown

Expected

  1. Call to init getting the first model
  2. Setting subscriptions based on the first model
  3. Executing the command returned from init
  4. Call to update getting a new model
  5. Setting subscriptions based on the new model
  6. Executing the returned command
  7. etc. …

Actual

  1. Call to init getting the first model
  2. Executing the command returned from init
  3. Call to update getting a new model
  4. Setting subscriptions based on the new model
  5. Setting subscriptions based on the first model

This bug was first reported in #1762 by @jatinderjit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions