Ports and Tasks

180 views
Skip to first unread message

Kurt Harriger

unread,
Dec 23, 2015, 1:30:36 PM12/23/15
to Elm Discuss
So based on the following http://elm-lang.org/guide/interop

I understand ports are supposed to be the preferred way that elm interacts with javascript. 

While it initially seems kinda backward:

* A port without an implementation can be used by javascript to execute elm code.
* A port with an implementation is used to execute of javascript code. 

This makes sense since its signals rather than code that is exported, thus:

* A port without an implementation defines a signal that can be used by javascript to trigger execution of elm code.
* A port with an implementation is used to export a signal that can trigger the execution of any javascript code which subscribes to this signal.

A few things I find a bit unclear: 
* Why is main not a port? 
* Why do we need to define a separate port to execute tasks (instead of returning these through main)? 
* Would this imply that my model update logic runs multiple times? once to export the view and once again to export the tasks?  
* Would any impure side-effects such as Debug.log in model updates be executed multiple times?
* How does elm determine that the port is used for tasks rather than javascript interop, function signature? 


Max Goldstein

unread,
Dec 23, 2015, 2:28:59 PM12/23/15
to Elm Discuss
Your initially backwards intuition stems from looking at ports from JavaScript's perspective. Think of them from Elm's perspective, which is how "incoming" and "outgoing" are oriented.

* Why is main not a port? 
Mostly because main existed before ports, but also because we didn't want to make it necessary to learn about ports to use main
 
* Why do we need to define a separate port to execute tasks (instead of returning these through main)? 
For similar reasons, main existed before tasks, and in the simplest case you don't have any tasks. Also, to keep things separate.
 
* Would this imply that my model update logic runs multiple times? once to export the view and once again to export the tasks?
In The Elm Architecture, the update function returns both a new model and some effects (essentially tasks), so it executes once.
 
* Would any impure side-effects such as Debug.log in model updates be executed multiple times?
Beyond the previous answer, you really just have to try it and see. Try not to focus on how often things get run
 
* How does elm determine that the port is used for tasks rather than javascript interop, function signature? 
Yup, all ports must have a function signature, so if it's a task or signal of tasks, they're handled by the runtime. Otherwise the values get passed of to JS callbacks.

These are good questions, thanks for asking! 

Noah Hall

unread,
Dec 23, 2015, 2:33:35 PM12/23/15
to elm-d...@googlegroups.com
As a sidenote, other implementations which can't use `main` often use ports instead, for example Elm on node and the react native project. 
--
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...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Kurt Harriger

unread,
Dec 23, 2015, 4:09:07 PM12/23/15
to elm-d...@googlegroups.com
I was initially unclear why there appeared to be multiple entry points and the implications this would have for executing things multiple times.  However the more I think about it and how "incoming and outgoing" are oriented I think it is starting to make more sense.  

If I understand correctly I think the magic here is that main and the tasks port are not functions to be invoked on every signal but rather they values which hold a signal object. This signal is created by running the elm code once and only once during evaluation.  Elm then subscribes to the signal object exported main and any ports that export tasks. Receiving a signal does not require calling main or tasks ever again.  

Update only runs once becasue start creates another signal effectsAndModel (via foldp) which when a Mouse.click is specified as input will subscribe to Mouse.clicks signal. In this case app.html and app.tasks are subscribers to this effectsAndModel signal and will be invoked as subscribers when a new value is created here, which in turn will invoke the elm listener attached to main which will re-render and the tasks port which will invoke the tasks.  

So when a signal arrives such as a mouse click elm is really pushing the mouse click into Mouse.clicks signal which invokes effectsAndModel (Signal.foldp) which then invokes app.html (Signal.map) and app.tasks (Signal.map) in arbitrary order (and the associated native handlers that have subscribed to app.html and app.tasks).  




Reply all
Reply to author
Forward
0 new messages