Stance on native APIs for 0.18?

939 views
Skip to first unread message

Wil C

unread,
Dec 5, 2016, 1:28:36 AM12/5/16
to Elm Discuss
I was reading the various message posts, and I happened upon this post on the stance of native modules from a year ago:

https://groups.google.com/forum/#!searchin/elm-dev/native$20author$3Aev...@gmail.com/elm-dev/1JW6wknkDIo/H9ZnS71BCAAJ

I was just wondering if there was an updated stance? Or this is pretty much the way going forward?

I'm all cool with the stance. But for some libraries, I hesitate to reimplement in elm, such as a parser/renderer for markdown or vega. It seems non-trivial. And I worry about having to track the upstream changes, since I'm neither a markdown for vega expert. I also noticed that the standard elm-markdown uses a minified JS version of marked.js in it as a native module. Even then, the renderer wasn't implemented in pure Elm. 

So right now, I'm using ports, as suggested, and a native module for commonmark.js. It makes some things a bit cumbersome, but it's working out so far. Just wanted to know if there were any thoughts from Elm maintainers about the topic going forward.

Wil

Richard Feldman

unread,
Dec 5, 2016, 3:06:42 AM12/5/16
to Elm Discuss
Yeah, my impression is that that post still reflects Evan's thinking on the matter. :)

Wil C

unread,
Dec 5, 2016, 10:09:29 AM12/5/16
to Elm Discuss
What about for non-trivial things like markdown parsers?

Wil

Richard Feldman

unread,
Dec 5, 2016, 11:19:14 AM12/5/16
to Elm Discuss
Looking at the evancz/elm-markdown parser, that seems like a case that warrants it, yeah.

Wil C

unread,
Dec 5, 2016, 11:36:59 AM12/5/16
to Elm Discuss
Do you know if there's going to be a guide on native modules? I just used elm-markdown as a guide, but I saw there were other conventions in other libraries with native modules.

I understand the hesitation in giving a guide on an escape hatch to native, since people will instinctively reach for it. Just was wondering if there was new thinking on it.

Richard Feldman

unread,
Dec 5, 2016, 12:22:42 PM12/5/16
to Elm Discuss

No new thinking on that as far as I'm aware...what are you looking to build?


--
You received this message because you are subscribed to a topic in the Google Groups "Elm Discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/elm-discuss/nuR4NnCVcMs/unsubscribe.
To unsubscribe from this group and all its topics, send an email to elm-discuss...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

W. Brian Gourlie

unread,
Dec 5, 2016, 4:28:43 PM12/5/16
to Elm Discuss
Not OP but a guide would be useful for contributing to existing libraries.  For example, the websocket library is lacking some features (https://github.com/elm-lang/websocket/issues/14) that I would like to try and implement.  The two things that suck right now: No documentation for the native framework, and, not sure if it would be in vain since Evan is highly opinionated (and rightly so) on API design, and I have no idea if whatever I implement would meet his standard.

Wil C

unread,
Dec 6, 2016, 12:18:04 PM12/6/16
to Elm Discuss
I'm building a document editor with executable code in it. So far, I have SQL embedded in Markdown. 

For markdown, I needed flexibility in changing the output from the standard HTML output, like adding extra info around a code block. I looked at elm-markdown, and found it didn't have this flexibility. In addition, it embedded a minified version of marked.js inside of it. 

Looked into parsing markdown briefly, and discovered it's not even a BNF, and would probably spend a lot of time writing the parser. I found commonmark.js. 

So now, either I write a ports for commonmark.js, or I write it as a native module. I asked about it here with no answers. 

I decided to write it as a native module with elm-markdown.js as a template. It's a bit messy in there, because 1) I'm proving out a concept, but also, 2) I'm not sure what is considered good practice. I had looked at a few other libs with native modules, and it seemed like they were using an API of some sort, rather than directly using namespaces like "_elm_lang$virtual_dom$Native_VirtualDom"

That's why I was asking. In cases where it's an integration library, like talking to the twitter API, I think it makes sense to write it entirely in Elm. Might be boring work, but it's doable. But what about things like parsers? If you find a parser in JS (ie. code above a certain complexity threshold) for a language, should you try to rewrite it in Elm? My guess is ideally, yes. But often times, I'm under a time crunch, or I'm more interested in proving out a concept to myself, so diving down to take the time to write a parser didn't make sense for me this time.

Wil

Rupert Smith

unread,
Dec 6, 2016, 2:32:49 PM12/6/16
to Elm Discuss
On Tuesday, December 6, 2016 at 5:18:04 PM UTC, Wil C wrote:
So now, either I write a ports for commonmark.js, or I write it as a native module. I asked about it here with no answers. 

I think if you write it as ports or native, you'll still need to map the AST between javascript and Elm. As a native module that could be done with a Decoder or by constructing the Elm AST in native code with Javascript. Perhaps Decoders are not so bad?

I don't think a parser is a side-effect. A parser is a pure function from String -> Ast, with no side effects.

Rupert Smith

unread,
Dec 6, 2016, 5:14:06 PM12/6/16
to Elm Discuss
The thing about ports for something like this is it feels a bit unnatural to invoke the port resulting in a Cmd. Then you'll need a subscription port to get the result back in, and have that pass it to your update function from where you can take it and place it in the model. That doesn't feel like a good way to call a function : String -> Ast.

I'd say the best solution is to implemented your parser in pure Elm. But if that is too much work, just hack together a native module that calls out to commonmark.js. You won't be able to publish your native module to elm packages, but that's ok, perhaps no-one else really wants your markdown with embedded SQL anyway, and if they do there is always elm-github-install. Some time down the road when you really need to share this amazing library, redo it in pure Elm. 
Message has been deleted

Mark Hamburg

unread,
Dec 7, 2016, 11:18:37 AM12/7/16
to elm-d...@googlegroups.com
Would it help if there were a standard mechanism to invoke JavaScript code as a task (or equivalently to make JavaScript code available as a task)? When the goal is to do some external computation, ports feel awkward as a mechanism. Something like:

port parseMarkdown : String -> Task Error Json.Decode.Value

(I'm handwaving here because I don't know what Error should be.)

One would wire up parseMarkdown in much the same way as other ports possibly using something like JavaScript promises to allow for long computations.

The arguable downside to this sort of interop is that it doesn't really provide a good way to build modules that can be distributed to others since the ports need to be connected in the app launch code. But that's true of other port types as well.

Mark

--
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+unsubscribe@googlegroups.com.

Vojtěch Král

unread,
Dec 8, 2016, 12:27:53 PM12/8/16
to Elm Discuss

Dne úterý 6. prosince 2016 23:14:06 UTC+1 Rupert Smith napsal(a):
The thing about ports for something like this is it feels a bit unnatural to invoke the port resulting in a Cmd. Then you'll need a subscription port to get the result back in, and have that pass it to your update function from where you can take it and place it in the model. That doesn't feel like a good way to call a function : String -> Ast.

I'd say the best solution is to implemented your parser in pure Elm. But if that is too much work, just hack together a native module that calls out to commonmark.js. You won't be able to publish your native module to elm packages, but that's ok, perhaps no-one else really wants your markdown with embedded SQL anyway, and if they do there is always elm-github-install. Some time down the road when you really need to share this amazing library, redo it in pure Elm.

This resonates with me very much. This is _exactly_ the reason why I made The Elm Alienation post on Reddit: https://www.reddit.com/r/elm/comments/5g3540/the_elm_alienation/

I also wanted to ask here about the status of the Native API but I'm seeing you guys already inquired.

Forcing people to rewrite everything in Elm is a terrible idea.


Dne středa 7. prosince 2016 17:18:37 UTC+1 Mark Hamburg napsal(a):
Would it help if there were a standard mechanism to invoke JavaScript code as a task (or equivalently to make JavaScript code available as a task)?

Yes! Very much! If this happened, I'd definitely revisit the decision to leave Elm.

Mark Hamburg

unread,
Dec 8, 2016, 1:28:22 PM12/8/16
to elm-d...@googlegroups.com
I was talking about this further with my coworkers and we more or less agreed that the key things that could help with Elm's interface to JavaScript were:

* Task ports. Tasks are a building block in a way that commands are not. Forcing all external interactions to be asynchronous makes it more clear that one is stepping outside and code could fail.

* A "foreign" value type that could capture a reference coming from JavaScript to be handed back in other calls. For example, though not a great JavaScript example, this could be a database connection. All operations on the database would occur via tasks. We just need an easy way for Elm to hold the handle to the database connection. This functionality would be better if the foreign types could be distinguished within Elm in their declaration — e.g.

    port type DBConnection

("port" reads wrong but I was avoiding introducing a new keyword.)

That said, one could also just use Foreign as a base type and use Elm code wrap it in more meaning for the type checker:

    type DBConnection = DBConnection Foreign

This, however, probably makes it harder to use the types safely in the task APIs.

Would those two features address everything needed? No. In particular, port wireup inhibits creating libraries. But it would make it much more straightforward for any individual project to build interfaces to JavaScript-based functionality.

Mark

--


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.

OvermindDL1

unread,
Dec 8, 2016, 1:44:21 PM12/8/16
to Elm Discuss
`opaque type DBConnection` perhaps would be the common way to write such a type that can only be passed in and passed out but not created.

Rupert Smith

unread,
Dec 8, 2016, 5:15:53 PM12/8/16
to Elm Discuss
On Thursday, December 8, 2016 at 5:27:53 PM UTC, Vojtěch Král wrote:
Dne středa 7. prosince 2016 17:18:37 UTC+1 Mark Hamburg napsal(a):
Would it help if there were a standard mechanism to invoke JavaScript code as a task (or equivalently to make JavaScript code available as a task)?

Yes! Very much! If this happened, I'd definitely revisit the decision to leave Elm.

I'm not sure that calling Javascript as a Task solves the issues you brought up. Specifically that an ordinary function call becomes asynchronous - you have to then schedule the task to be run and get back the result as a msg to your update function. Sometimes you just want to call a foreign function and get the answer back right away.

Of course, with native modules it is very easy to do this already with Elm. You just can't publish a package with it in to the official repo. 

Wil C

unread,
Dec 8, 2016, 6:04:12 PM12/8/16
to Elm Discuss


So now, either I write a ports for commonmark.js, or I write it as a native module. I asked about it here with no answers. 

I think if you write it as ports or native, you'll still need to map the AST between javascript and Elm. As a native module that could be done with a Decoder or by constructing the Elm AST in native code with Javascript. Perhaps Decoders are not so bad?

In the case of using commonmark.js, I didn't use a decoder. Taking a page out of the elm-markdown playbook, I call directly into VirtualDom's js calls. My guess is that Evan did it as a hack. And since it's not a published API, I don't expect it to stick around. Reaching into a private API is usually bad news. I chose not to write decoders in this case, because I'm using commonmark.js already, so it's not like I could share the code as a lib. And it's admittedly a shortcut.

In the case of parsing SQL, I did end up using a decoder. I sent the sql string into a port, had it parsed and returned as JSON representing an AST, that fed back into a subscription port that I then decoded into union types.
 
I don't think a parser is a side-effect. A parser is a pure function from String -> Ast, with no side effects.

Technically, no. That's why I was asking about a native module API, since I just copied elm-markdown.
 
The thing about ports for something like this is it feels a bit unnatural to invoke the port resulting in a Cmd. Then you'll need a subscription port to get the result back in, and have that pass it to your update function from where you can take it and place it in the model. That doesn't feel like a good way to call a function : String -> Ast.

Well, since there's no official documentation on a native module API, ports is what I can rely on. But from a semantics point of view, since I'm calling out to something that might have a side effect, it makes sense. It's just the mechanics is a bit awkward. I've had the pleasure of swimming in his design decisions in Elm so far, and he's built up enough cred with me that I think he'll figure something out.

I was just looking for some guidance as to what to implement in pure elm, and what to leverage native modules for. Even in other languages where new libraries are implemented completely in that language (like ruby, per the original post on native modules a year ago), there are libraries that call out. The main one that comes to mind is the Linear Algebra Package (LAPACK) originally written in Fortran, but most languages that use it now are usually just wrappers around it. I just wondered where Elm community drew the line.

Wil

Rupert Smith

unread,
Dec 9, 2016, 6:12:43 AM12/9/16
to Elm Discuss
On Thursday, December 8, 2016 at 5:27:53 PM UTC, Vojtěch Král wrote:
This resonates with me very much. This is _exactly_ the reason why I made The Elm Alienation post on Reddit: https://www.reddit.com/r/elm/comments/5g3540/the_elm_alienation/

If I can quote from that: "In a nutshell, Elm needs unsafe."

I mostly agree with this, but have some reservations.

The existing native API is easy enough to figure out, just look at any 'native' module implementation. Basically  you follow the conventions you see for namespaing you javascript code and wrapping functions with helpers like F2, F3 and so on, and return an object containing all the functions you want to expose to Elm.

Also code does not need to be made asynchronous to be made type-safe, you could use Result for synchronous calls. Just map all exceptions to Err, and succesfull calls to Ok.

It would be nice if we could just mark our own native modules as 'unsafe' and have an 'unsafe' section on package.elm-lang.org to share them.

From what I've read about it, there is a another aspect to this that the keyword 'unsafe' doesn't quite cover. Elm could also run in a different environment to browser + javascript. To take a hypothetical example, it could be ported for writing native Windows applications. In which case the native parts of the platform that are currently written in javascript might end up getting rewritten as say C#. Then the exact same Elm code could produce a web application or a native windows application. For Android it would be Java, you get the idea.

So we'd need a keyword and understanding about lack of potential forward compatability that expresses this, were there to be a way to provide some degree of official recognition that people want to write and share native code. Perhaps its an 'unsafe javascript elm18 module' that we need...

I like that Evan has had the foresight to prevent Elm being locked in to its current runtime environment in order to keep options open for the future. If I need to delve into hacking javascript to do something that I can't do otherwise, I'm happy enough with taking the risk of no forward compatability, because I'm using the version of Elm that I currently have, to solve problems that I currently need to solve, and finding that Elm is good enough to be worth making an exception for. As I say, there is always elm-github-install for the hackers.

 

Vojtěch Král

unread,
Dec 9, 2016, 10:31:15 AM12/9/16
to Elm Discuss


Dne pátek 9. prosince 2016 12:12:43 UTC+1 Rupert Smith napsal(a):
On Thursday, December 8, 2016 at 5:27:53 PM UTC, Vojtěch Král wrote:
This resonates with me very much. This is _exactly_ the reason why I made The Elm Alienation post on Reddit: https://www.reddit.com/r/elm/comments/5g3540/the_elm_alienation/

If I can quote from that: "In a nutshell, Elm needs unsafe."

I mostly agree with this, but have some reservations.

The existing native API is easy enough to figure out, just look at any 'native' module implementation. Basically  you follow the conventions you see for namespaing you javascript code and wrapping functions with helpers like F2, F3 and so on, and return an object containing all the functions you want to expose to Elm.

Also code does not need to be made asynchronous to be made type-safe, you could use Result for synchronous calls. Just map all exceptions to Err, and succesfull calls to Ok.

It would be nice if we could just mark our own native modules as 'unsafe' and have an 'unsafe' section on package.elm-lang.org to share them. 
 
Yup. I didn't realize Tasks are this async, thanks for pointing that out. +1 to your email.

Mark Hamburg

unread,
Dec 9, 2016, 3:07:33 PM12/9/16
to elm-d...@googlegroups.com
While there are certainly times when synchronous calls would have been nice, I recognize that having synchronous behavior for potentially mutable external state also tends to imply a lot about execution order — something that a pure functional language expects to be more free about. Hence, I think it's reasonable to force operations that need to deal with the external world to be asynchronous.

Mark


--


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.

Duane Johnson

unread,
Dec 9, 2016, 5:06:52 PM12/9/16
to elm-d...@googlegroups.com

On Fri, Dec 9, 2016 at 1:07 PM, Mark Hamburg <mhamb...@gmail.com> wrote:
operations that need to deal with the external world

The one thing I don't like about Elm is the feeling that it's *hard work* to deal with the world. I wish it felt like a happy place, a tool I would easily reach for, or a pleasant experience.

Rupert Smith

unread,
Dec 12, 2016, 9:16:42 AM12/12/16
to Elm Discuss
On Friday, December 9, 2016 at 8:07:33 PM UTC, Mark Hamburg wrote:
While there are certainly times when synchronous calls would have been nice, I recognize that having synchronous behavior for potentially mutable external state also tends to imply a lot about execution order — something that a pure functional language expects to be more free about. Hence, I think it's reasonable to force operations that need to deal with the external world to be asynchronous.

Consider monads in other fp langauges. You don't need to have an asynchronous model to work with external state and side effects.

I suppose you could describe Elm's event driven loop as a monad, in the sense that it chains together sequences of functions over messages.

Mark Hamburg

unread,
Dec 12, 2016, 11:19:31 PM12/12/16
to elm-d...@googlegroups.com
One doesn't need them to be asynchronous but making them asynchronous helps reinforce the notion that this is happening outside the Elm universe. And if you want monads, Elm's tasks are monadic.

Mark

--
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+unsubscribe@googlegroups.com.

Mark Hamburg

unread,
Dec 12, 2016, 11:24:03 PM12/12/16
to elm-d...@googlegroups.com
A better way of putting this: Haskell's IO monad structures a particular set of interactions with the outside world. By making all foreign interactions go through tasks, Elm could use its task monad to structure interactions with the outside world. The difference then is that Haskell has more syntactic sugar around monads than Elm does.

Mark

Rupert Smith

unread,
Dec 13, 2016, 10:30:11 AM12/13/16
to Elm Discuss
On Tuesday, December 13, 2016 at 4:19:31 AM UTC, Mark Hamburg wrote:
One doesn't need them to be asynchronous but making them asynchronous helps reinforce the notion that this is happening outside the Elm universe. And if you want monads, Elm's tasks are monadic.

I really want to disagree with you because it makes it a PITA when you just want to call a pure function written in js, but I have to concede that you are right. If making simple synchronous calls to javascript was the supported mechanism for interfacing, the elm package repo would very quickly get poluted with js code that causes runtime exceptions and it not portable. 

Another advantage is that it encourages people to write pure functions in Elm in order to share their work, and we all benefit from that.

Best thing to tell people looking for 'unsafe' modules in Elm then, is to tell them that we already have them it is just that the keyword is 'native', and that the platform is protected from such unsafe code by not officially supporting it.

Joey Eremondi

unread,
Dec 13, 2016, 10:42:23 AM12/13/16
to elm-d...@googlegroups.com
the elm package repo would very quickly get poluted with js code that causes runtime exceptions

But, Tasks have error handling built into them. We could do something similar with synchronous code, just catch any exceptions thrown, and treat the value in Elm as something like a Result.

Mark Hamburg

unread,
Dec 13, 2016, 11:06:21 PM12/13/16
to elm-d...@googlegroups.com
Then people would complain that all native calls returned Results rather than the type they wanted returned.

Mark

On Tue, Dec 13, 2016 at 7:42 AM, Joey Eremondi <joey.e...@gmail.com> wrote:
the elm package repo would very quickly get poluted with js code that causes runtime exceptions

But, Tasks have error handling built into them. We could do something similar with synchronous code, just catch any exceptions thrown, and treat the value in Elm as something like a Result.

--

Mark Hamburg

unread,
Dec 13, 2016, 11:09:03 PM12/13/16
to elm-d...@googlegroups.com
I basically look on it as code that exists to make Elm run at all. That's basically what Native exists for. (Native also plays games with the type system but that's another matter.)

And then there's external code that I would like to run that isn't critical to Elm being Elm. That seems a natural place to deploy Tasks.

Mark

Rupert Smith

unread,
Dec 14, 2016, 5:48:06 AM12/14/16
to Elm Discuss


On Tuesday, December 13, 2016 at 3:42:23 PM UTC, Joey Eremondi wrote:
the elm package repo would very quickly get poluted with js code that causes runtime exceptions

But, Tasks have error handling built into them. We could do something similar with synchronous code, just catch any exceptions thrown, and treat the value in Elm as something like a Result.

> the elm package repo would very quickly get poluted with js code that causes runtime exceptions _* and is not portable *_

Result would work, but the not portable bit is equally impoertant.
 

Desmond D'Souza

unread,
Dec 14, 2016, 1:00:14 PM12/14/16
to Elm Discuss
I would love to be able to make synchronous functional calls to js and get a Result back. 

Taking simple clean synchronous functional code (e.g. if it were all in Elm), and being forced to chop out bits into async calls with async Msg callbacks (just because it is not all in Elm) impacts my code in unpleasant ways: 
  1. weird async bugs: will my originally sync call to layout(graph) get the layout answer back after the user has switched to another graph?
  2. pollution of model and update: 
    • I need to stuff into my model bits that were simple transient local variables before, and maintain those extra bits everywhere in my code. Forget to clear them somewhere, and chunks of my code like another update branch or a view function, think I have a current graph waiting for a layout.
    • I add more checks into my update to deal with possibly getting intervening unrelated async inputs
  3. API bloat: why does AndHereIsYourLayoutBack need to be part of my API, when that is already explicit through the outgoing call mechanism (e.g. via something like a synchronous port, or some alternative)
I think #1 would be somewhat alleviated by synchronous tasks from this thread, but #2 and #3 remain. 

Properly supporting this use case would be good for Elm. Sure, I could abuse it to call a stateful js api, causing problems if the Elm compiler moves expression evaluation order around, hence I use some unsafe marker either as an annotation to myself or to the compiler.

Joey Eremondi

unread,
Dec 14, 2016, 1:18:01 PM12/14/16
to elm-d...@googlegroups.com
Sure, I could abuse it to call a stateful js ap

Which you can currently do with Cmd ports! We'd just want to wrap it in some type like Task or Cmd, and then it would be nicely segregated from pure code.

--

Rupert Smith

unread,
Dec 14, 2016, 2:30:48 PM12/14/16
to Elm Discuss
On Wednesday, December 14, 2016 at 6:00:14 PM UTC, Desmond D'Souza wrote:
I would love to be able to make synchronous functional calls to js and get a Result back.

Would you want to publish this code to elm-package?

Would the javascript your package calls be included in the package? 

Desmond D'Souza

unread,
Dec 14, 2016, 11:24:49 PM12/14/16
to Elm Discuss


On Wednesday, December 14, 2016 at 12:18:01 PM UTC-6, Joey Eremondi wrote:
Sure, I could abuse it to call a stateful js ap

Which you can currently do with Cmd ports! We'd just want to wrap it in some type like Task or Cmd, and then it would be nicely segregated from pure code.

Correct. I phrased that badly, I meant
 "Sure, I could call supposedly pure js code to compute a value, but that js happens to have some unintended side effect or stateful behavior, causing problem if the Elm compiler ...".
 
Task or Cmd would still be the right way to do all intentional side effects or communication. But calling some js loaded in the browser right alongside my Elm code to synchronously compute layout(graph) should be handled as similarly as possible to doing all the computation in Elm itself. 
 

On Wed, Dec 14, 2016 at 10:00 AM, Desmond D'Souza <des...@dsouzaville.com> wrote:
I would love to be able to make synchronous functional calls to js and get a Result back. 

Taking simple clean synchronous functional code (e.g. if it were all in Elm), and being forced to chop out bits into async calls with async Msg callbacks (just because it is not all in Elm) impacts my code in unpleasant ways: 
  1. weird async bugs: will my originally sync call to layout(graph) get the layout answer back after the user has switched to another graph?
  2. pollution of model and update: 
    • I need to stuff into my model bits that were simple transient local variables before, and maintain those extra bits everywhere in my code. Forget to clear them somewhere, and chunks of my code like another update branch or a view function, think I have a current graph waiting for a layout.
    • I add more checks into my update to deal with possibly getting intervening unrelated async inputs
  3. API bloat: why does AndHereIsYourLayoutBack need to be part of my API, when that is already explicit through the outgoing call mechanism (e.g. via something like a synchronous port, or some alternative)
I think #1 would be somewhat alleviated by synchronous tasks from this thread, but #2 and #3 remain. 

Properly supporting this use case would be good for Elm. Sure, I could abuse it to call a stateful js api, causing problems if the Elm compiler moves expression evaluation order around, hence I use some unsafe marker either as an annotation to myself or to the compiler.


On Wednesday, December 14, 2016 at 4:48:06 AM UTC-6, Rupert Smith wrote:


On Tuesday, December 13, 2016 at 3:42:23 PM UTC, Joey Eremondi wrote:
the elm package repo would very quickly get poluted with js code that causes runtime exceptions

But, Tasks have error handling built into them. We could do something similar with synchronous code, just catch any exceptions thrown, and treat the value in Elm as something like a Result.

> the elm package repo would very quickly get poluted with js code that causes runtime exceptions _* and is not portable *_

Result would work, but the not portable bit is equally impoertant.
 

--
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.

Desmond D'Souza

unread,
Dec 15, 2016, 12:03:34 AM12/15/16
to Elm Discuss


On Wednesday, December 14, 2016 at 1:30:48 PM UTC-6, Rupert Smith wrote:
On Wednesday, December 14, 2016 at 6:00:14 PM UTC, Desmond D'Souza wrote:
I would love to be able to make synchronous functional calls to js and get a Result back.

Would you want to publish this code to elm-package?

Yes. 
 

Would the javascript your package calls be included in the package? 

I don't know, but do have a naive answer. If I had written all of it in Elm, split into App.elm and GraphLayout.elm, I could publish both modules bundled into a single package or split into two, and Elm + elm-package spells out what a package user needs to know and do in both cases. If GraphLayout is in javascript, the overall package story should stay as close as reasonably possible for the package user, and Elm + elm-package should spell out what that user needs to know and do.

Mark Hamburg

unread,
Dec 15, 2016, 12:40:17 PM12/15/16
to elm-d...@googlegroups.com
Having external compute run asynchronously opens the possibility of having it run in parallel some day. That said, if Elm were to emphasize that sort of programming, it might drive some shifts in how other pieces are structured. The world is going async — see node.js — but it's a painful process. Tasks might be enough but I don't know that anyone has written a complex process around tasks and any such process wouldn't leverage the Elm debugger. A bigger problem is that once you ask for something to be computed, it really helps if there is a way to say "nevermind". Reactive networks also help hide some of the management issues for this sort of work but Elm has been moving away from those.

So, I embrace async tasks but I think they also then need to be embraced by the language/runtime/app-architecture.

Mark

--

Roland Kuhn

unread,
Dec 15, 2016, 12:57:08 PM12/15/16
to elm-d...@googlegroups.com
Hi Mark (and others),

15 dec. 2016 kl. 18:40 skrev Mark Hamburg <mhamb...@gmail.com>:

Having external compute run asynchronously opens the possibility of having it run in parallel some day.

As much as I sympathise with the notion of encapsulating “dirty” code and marking it out, making it asynchronous is the wrong direction: these calls are performing uncontrolled side-effects, hence running them in parallel is the worst choice possible.

Another observation is that taking unreasonable code (i.e. code that cannot easily be reasoned about) and sticking it into a monad does not make it any more reasonable. If calling unreasonable code is the goal, then there is no improvement to be had over just calling it.

Regards,

Roland

To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Joey Eremondi

unread,
Dec 15, 2016, 1:27:59 PM12/15/16
to elm-d...@googlegroups.com
sticking it into a monad does not make it any more reasonable

The thing is, it's not about calling unreasonable code, it's about calling *potentially* unreasonable code. Putting it in a Monad doesn't make it more reasonable, but it means that the reasonability of pure Elm code is not compromised, and unreasonable JS can't make Elm behave in an unreasonable way. And making it return a Result (or similar, like Task's error type) ensures that the uses of this code *must* handle any unreasonably that occurs.

Likewise, with parallelism, the encapsulation does help. The monadic andThen function is the perfect tool for chaining operations together into blocks which must be run atomically, and while you can get race conditions, the monadic structure ensures that those ill effects never leak into pure code.

Roland Kuhn

unread,
Dec 15, 2016, 1:44:20 PM12/15/16
to elm-d...@googlegroups.com
15 dec. 2016 kl. 19:27 skrev Joey Eremondi <joey.e...@gmail.com>:

sticking it into a monad does not make it any more reasonable

The thing is, it's not about calling unreasonable code, it's about calling *potentially* unreasonable code.

Which is the same thing: being potentially unreasonable means that we cannot reason about it.

Putting it in a Monad doesn't make it more reasonable, but it means that the reasonability of pure Elm code is not compromised, and unreasonable JS can't make Elm behave in an unreasonable way.

Wrong: the Elm code that chains off those Tasks is held hostage by the unreasonability of the called code. If calling JS is “just a Task” then suddenly Tasks don’t compose anymore in the sense that pure functions would. You cannot compose multiple impure actions in a pure way with the expectation that that makes the impure actions composable.

And making it return a Result (or similar, like Task's error type) ensures that the uses of this code *must* handle any unreasonably that occurs.

Again wrong: just having a certain type does not enable client code to handle the fallout—because the effects of JS code are literally arbitrary. The only achieved effect is that the fallout is signaled in the type system. But then if most of the code is reasonable despite being JS, most people will just run these Tasks as if they’re fine anyway, and the function of the type marker is lost—it just makes life a little more miserable where people are forced to jump through hoops.

To make it clear, I am not proposing a certain strategy, I am not involved in the Elm community enough for that, but I’d like to counter certain arguments that I have seen go wrong. Placing effectful code in monads is not a solution because the underlying problem fundamentally cannot be solved. A solution would mean to devise an algebra for the domain of effects that is to be modeled and to thoroughly understand it (including its limitations). Calling arbitrary code cannot be treated like that since it is arbitrary.

Regards,

Roland

To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Vojtěch Král

unread,
Dec 16, 2016, 7:39:24 AM12/16/16
to Elm Discuss

Dne čtvrtek 15. prosince 2016 19:44:20 UTC+1 Roland Kuhn napsal(a):

Again wrong: just having a certain type does not enable client code to handle the fallout—because the effects of JS code are literally arbitrary. The only achieved effect is that the fallout is signaled in the type system. But then if most of the code is reasonable despite being JS, most people will just run these Tasks as if they’re fine anyway, and the function of the type marker is lost—it just makes life a little more miserable where people are forced to jump through hoops.
 
That's not entirely true. I agree that generaly the problem of JS code having arbitrary side-effects cannot be solved statically/automatically, but these type system facilities (Task, Result) do help, methinks. They can be useful for handling errors that are expected as well as, for example, catching JS exceptions thrown down the stack. I definitely wouldn't mark them useless.

Anyhow, did anyone manage to get Evan's opinion on this thread?

Simon

unread,
Dec 16, 2016, 9:07:53 AM12/16/16
to Elm Discuss
> * A "foreign" value type that could capture a reference coming from JavaScript to be handed back in other calls.

We already have that with Json.Encode.Value, and it can be passed to from javascript: see this example for Google maps, which I copied from how Evan built websockets

Simon


On Thursday, 8 December 2016 19:28:22 UTC+1, Mark Hamburg wrote:
I was talking about this further with my coworkers and we more or less agreed that the key things that could help with Elm's interface to JavaScript were:

* Task ports. Tasks are a building block in a way that commands are not. Forcing all external interactions to be asynchronous makes it more clear that one is stepping outside and code could fail.

* A "foreign" value type that could capture a reference coming from JavaScript to be handed back in other calls. For example, though not a great JavaScript example, this could be a database connection. All operations on the database would occur via tasks. We just need an easy way for Elm to hold the handle to the database connection. This functionality would be better if the foreign types could be distinguished within Elm in their declaration — e.g.

    port type DBConnection

("port" reads wrong but I was avoiding introducing a new keyword.)

That said, one could also just use Foreign as a base type and use Elm code wrap it in more meaning for the type checker:

    type DBConnection = DBConnection Foreign

This, however, probably makes it harder to use the types safely in the task APIs.

Would those two features address everything needed? No. In particular, port wireup inhibits creating libraries. But it would make it much more straightforward for any individual project to build interfaces to JavaScript-based functionality.

Mark
On Thu, Dec 8, 2016 at 9:27 AM Vojtěch Král <vojtechkr...@gmail.com> wrote:

Dne úterý 6. prosince 2016 23:14:06 UTC+1 Rupert Smith napsal(a):
The thing about ports for something like this is it feels a bit unnatural to invoke the port resulting in a Cmd. Then you'll need a subscription port to get the result back in, and have that pass it to your update function from where you can take it and place it in the model. That doesn't feel like a good way to call a function : String -> Ast.

I'd say the best solution is to implemented your parser in pure Elm. But if that is too much work, just hack together a native module that calls out to commonmark.js. You won't be able to publish your native module to elm packages, but that's ok, perhaps no-one else really wants your markdown with embedded SQL anyway, and if they do there is always elm-github-install. Some time down the road when you really need to share this amazing library, redo it in pure Elm.
This resonates with me very much. This is _exactly_ the reason why I made The Elm Alienation post on Reddit: https://www.reddit.com/r/elm/comments/5g3540/the_elm_alienation/

I also wanted to ask here about the status of the Native API but I'm seeing you guys already inquired.

Forcing people to rewrite everything in Elm is a terrible idea.


Dne středa 7. prosince 2016 17:18:37 UTC+1 Mark Hamburg napsal(a):
Would

it help if there were a standard mechanism to invoke JavaScript code as

a task (or equivalently to make JavaScript code available as a task)?

Yes! Very much! If this happened, I'd definitely revisit the decision to leave Elm.









Mark Hamburg

unread,
Dec 16, 2016, 11:32:33 AM12/16/16
to elm-d...@googlegroups.com
My view of the ideal world here with respect to JavaScript is that JavaScript (or any other foreign language host) is basically a separate universe that gets orchestrated by and communicates with Elm. Since Elm is implemented as compiling to JavaScript and it runs within the JavaScript universe, we can't actually protect it from ill-behavior in that universe but that's an artifact of implementation. If one pretends that the Elm and JavaScript universes are separate — because some day they might be — then one needs to recognize that it is very difficult to arrange for synchronous behavior in another universe. Many systems allow one to do it, but it tends to block in ugly ways and if at all possible you want to avoid it. So, I think it's pretty natural to view Elm's interaction with an external universe as consisting of tasks to perform (asynchronously) and potentially subscriptions by which to watch that universe — again asynchronously.

One of the challenges in multi-universe systems is object lifetimes. Cross-universe GC is hard as a general problem. If, however, we say that the JavaScript universe is subordinate to the Elm universe in that Elm can hold references to JavaScript objects but not the other way around, then this problem goes away.

One area where I will admit this notion is less clear is how animation or anything requiring tight — i.e., synchronous — coupling should work. In this case, the JavaScript universe essentially wants to fire off a message to Elm and then block waiting for a return value. That's a pain for the JavaScript side but it's what is essentially happening now anyway. If animation synchronization didn't matter, then one could imagine a version in which the JavaScript universe would fire off strobes at animation frames to which the Elm universe could respond by calling view and pushing a new HTML tree back to JavaScript. The JavaScript universe would not, however, block in the meantime. The net result might be pretty similar to where things are now but it feels like there could be slightly greater opportunity for skew.

Mark

Desmond D'Souza

unread,
Dec 16, 2016, 2:32:11 PM12/16/16
to Elm Discuss
Sorry to be dense, but ... in what actual scenario would the following cause problems, assuming I am writing for the browser?
  • Allow Elm code to make synchronous function calls to js, expecting a js value wrapped in a Result
    • Use encoders / decoders if needed at the boundary, a decode failure yielding a Result.Err
  • The Elm-side type signatures of the outgoing call and the Result expected back are the complete contract
  • On the elm-to-js-bridge wrap a try-catch around the call to yield either Result.Ok or Result.Err
  • If the concern is the Elm compiler's right to shuffle evaluation order in ways the side-effect prone js might not like, use the "unsafe" or "native" annotation to guide the user (and optionally or longer term, the compiler).
I don't see how refactoring my Model, Msg, update in order to use an async Task / Cmd + Msg callback is a better choice, specially since I would want to know if things went wrong on the js side anyway.
To unsubscribe from this group and stop receiving emails from it, send an email to elm-discuss...@googlegroups.com.

Rupert Smith

unread,
Dec 20, 2016, 9:03:00 AM12/20/16
to Elm Discuss
On Friday, December 16, 2016 at 7:32:11 PM UTC, Desmond D'Souza wrote:
I don't see how refactoring my Model, Msg, update in order to use an async Task / Cmd + Msg callback is a better choice, specially since I would want to know if things went wrong on the js side anyway.

I came accross this talk post yesterday and thought it was worth sharing here as it seems relevant to the discussion:


In short, message passing concurrency as inspired by Concurrent Programming in ML was chosen as the preferred framing of concurrency to reduce accidental complexity. I've only looked through the slide deck not watched the video yet, but it looks interesting.

One for the christmas reading list perhaps:

Reply all
Reply to author
Forward
0 new messages