+1 for Task ports. On Friday, 14 April 2017 20:32:24 UTC+2, Nicholas Hollon wrote: > > The process: > > 1. Share your ideas, experience, & code on elm-discuss. > 2. Accept that you have no direct influence over what Evan works on next. > 3. Look at the release history <http://elm-lang.org/blog> for Elm. Notice > that changes happen slowly. Notice that improvements to the JavaScript > interface (ports, tasks, subscriptions) are spaced out by at least a year. > Notice that 0.17 has only been out for about a year. > 4. Remember that things are going to get better! Just because something > isn't being worked on right this minute doesn't mean that it isn't going to > be improved in the future. > 6. Do things in life that make you happy. If it upsets you that Elm lacks > something you think is super important, maybe take a break and come back > later. > > > > On Friday, April 14, 2017 at 10:24:46 AM UTC-7, Conner Ruhl wrote: >> >> What is the process for requesting these sort of features? Is there one? >> >> On Saturday, August 13, 2016 at 10:31:07 AM UTC-5, James Wilson wrote: >>> >>> The problem >>> >>> ports as they stand are fundamentally incompatible with Tasks. Being >>> backed by Cmd's, they are harder to compose. A frustration of mine is that >>> often we are directed to "just use ports" when a proper interface to some >>> native API is not yet available, but this leads to our Msg types growing >>> and more significant changes being required when eventually the proper >>> interface is made available. >>> >>> Also, many JS interop things I find myself wanting to do are >>> fundamentally one-shot functions which I expect a result back into Elm from >>> immediately, or otherwise just want to compose with other Task based >>> things. Some examples that come to mind of one-shot tasks you may want to >>> compose rather than use the streaming interface that ports provide: >>> >>> - Getting items from local/sessionStorage >>> - .. really, most things involving working with the Web API that >>> arent yet implemented in Elm. >>> - Embedding JS widgets into Elm elements >>> - Using a JS library for doing things like hashing passwords or >>> obtaining some data back from some custom service >>> - Interacting with things like Electron for creating apps that can >>> run in the desktop and interact with the filesystem etc. >>> >>> >>> The solution >>> >>> Task ports. The idea is that these are defined the same way that Ports >>> in elm currently are, but they return a Task type rather than a Cmd or Sub >>> type. On the JS Side, we attach a function to the Elm app that returns a >>> Promise, and on the Elm side we wait for the Promise returned to reject or >>> resolve, and marhsall the error or result from the promise into the error >>> or result type required by the Task type of the port. >>> >>> Let's see how this might work: >>> >>> >>> *Ports.elm:* >>> >>> port apiSession: Task String SessionId >>> >>> >>> >>> *Main.elm:* >>> >>> import Ports >>> import Json.Decode as Decode >>> import Task exposing (andThen) >>> >>> >>> -- get an API session from JS land and make an http request using it >>> -- given some path and a decoder to decipher the result: >>> apiRequest : String -> Decoder a -> Task ApiError a >>> apiRequest path decoder = >>> let >>> headers sessId = >>> [ ("Content-Type", "application/json") >>> , ("MyApp-SessionId", sessId) >>> ] >>> >>> >>> req sessId = Http.send Http.defaultSettings >>> { verb = "POST" >>> , headers = headers sessId >>> , url = path >>> } >>> >>> >>> decodeResponse res = Decode.decodeString decoder -- ...handle error >>> etc >>> in >>> Ports.apiSession `andThen` req `andThen` decodeResponse >>> >>> >>> *App.js:* >>> >>> Elm.Main.ports.apiSession = function(){ >>> return new Promise(function(resolve,reject){ >>> >>> >>> var sess = localStorage.getItem("sessionId"); >>> if(!sess) reject("NO_SESSION"); >>> else resolve(sess); >>> >>> >>> }); >>> } >>> >>> var app = Elm.Main.fullscreen(); >>> >>> >>> >>> >>> Here, we use a tiny bit of JS to access localStorage and pull out a >>> session ID. This function is used whenever the apiRequest Task is performed >>> in Elm, and composes nicely into our apiRequest without the need for a >>> complicated effect manager or threading a sessionId through everywhere just >>> because we need to get it from a Cmd based port. >>> >>> One of the nice things about this is that there is minimal refactoring >>> to do for those things that do eventually receive coverage in the Elm Web >>> API - you're just swapping out Tasks for other Tasks. As the Web API will >>> always be changing, I think that having a nice way to make JS polyfills >>> like this will always have some value, let alone for interacting with >>> libraries written in JS that haven't or won't ever be ported to Elm. >>> >>> Elm would continue to make the same guarantees as with other ports; if >>> the task port can't marshall the response back into Elm an error would be >>> thrown along the same lines as is currently done via ports. >>> >>> Summary >>> >>> - regular ports only let you send data off or receive data back, not >>> both. >>> - Cmd's and Sub's are not composable >>> - Task based ports allow you to create a new Task that is backed by JS >>> - Task based ports allow for better composition and less friction when >>> the backing JS is eventually implemented in Elm. >>> >>> I'd love to hear what people think about this. Perhaps I'm missing some >>> big issues with the idea for instance, or maybe it's an awesome idea :) >>> What do you all think? >>> >>>
-- 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
