This is proposed as a simplified alternative to https://gist.github.com/mgold/f3527359996fdf295843 - what if instead of renaming Mailbox
, we just didn't have a name for that thing?
Rationale:
- From an API perspective, it's important that the function for instantiating a
Signal
returns two distinct values: theSignal
and a way to send aMessage
to it. Mailbox
(and alternativelyDispatcher
) give a type alias to that return value.- In practice, we never compose Mailboxes or Dispatchers directly; we simply read the two values out of them and then immediately discard them.
- Despite this, I hear people saying things like "Do I need a Mailbox for that?" when the real question is "I want to create a Signal; how do I do that?" The type alias seems to be a red herring that leads people down the wrong path.
- I've gotten the best results from telling people "Focus on the Signal. Do you need to create a new Signal out of thin air? If so, here's the function that does that." (Currently that function is called
Signal.mailbox
, which people then have to memorize.) - We could embrace this by removing the type alias and instead have the
Signal
creation function use the standard approach for returning two things: have it return a tuple.
The specific proposal, relative to the 0.16 Signal
API:
1. Remove Signal.Address
and Signal.Mailbox
2. Replace Signal.mailbox
with Signal.create
, which simply returns a tuple:
create : a -> (Signal a, a -> Message)
3. See Max's gist for the refactors related to Address
being gone.
In practice, Mailbox
is essentially always used like so:
openDatepickerMailbox =
Signal.mailbox ()
...
port openDatepicker : Signal ()
port openDatepicker =
openDatepickerMailbox.signal
...
view openDatepickerMailbox.address actions model
In this tuple world, we would instead do:
(openDatepicker, sendToOpenDatepicker) =
Signal.create ()
...
port openDatepicker : Signal ()
port openDatepicker =
openDatepicker
...
view sendToOpenDatepicker actions model
As far as I know, there is currently no way to add a type annotation to a destructured tuple. Using this style would thus presumably lead to an unresolvable warning for a missing toplevel annotation.
With the caveat that any new language feature imposes a burden, it does seem like allowing destructured type annotations would be useful and intuitive anyway, so I would propose introducing the following:
(openDatepicker : Signal (), sendToOpenDatepicker : () -> Message) =
(openDatepicker, sendToOpenDatepicker) =
Signal.create ()
Just a thought.