V2 of promhx

279 views
Skip to first unread message

Justin Donaldson

unread,
Nov 17, 2015, 3:15:42 PM11/17/15
to Haxe
Hey folks,

I'm working on a new version of promhx.  The first version up right now uses some new haxe supported syntax to simplify a few constraint-related typing details.  It also fixes issues I was having with java and csharp.

You can find the branch here:

There's been a number of requests for features, additions, etc.  If you had ideas or issues that you think should make it into v2, feel free to talk about them in this thread.

Message has been deleted

Andy Li

unread,
Nov 18, 2015, 1:27:44 PM11/18/15
to haxe...@googlegroups.com
Hey, a new version of promhx is exciting to me!
Before I look into the changes, I notice that you haven't switched to the new ppa (ppa:haxe/releases) in travis ;)

Best,
Andy

--
To post to this group haxe...@googlegroups.com
http://groups.google.com/group/haxelang?hl=en
---
You received this message because you are subscribed to the Google Groups "Haxe" group.
For more options, visit https://groups.google.com/d/optout.

Andy Li

unread,
Nov 18, 2015, 1:29:26 PM11/18/15
to haxe...@googlegroups.com
Or even better, I believe you can use the built-in haxe support in travis, like https://github.com/andyli/HaxeCI/blob/master/.travis.yml
Message has been deleted

Justin Donaldson

unread,
Nov 18, 2015, 7:19:08 PM11/18/15
to Haxe
Sure thing Andy, I really appreciate your work on Travis support!

I think I would also benefit from an update to my asynchronous testing ability.  I'm using an old version of Franco's utest I believe.  What's the latest on haxe unit tests?  Anything else I should consider?

Franco Ponticelli

unread,
Nov 19, 2015, 1:30:37 AM11/19/15
to Haxe
Stick to the old and solid ;)
Message has been deleted
Message has been deleted
Message has been deleted

Justin Donaldson

unread,
Nov 28, 2015, 10:47:30 PM11/28/15
to Haxe
Yeah, if it ain't broke.. don't fix it.

Anyways, I have a pretty decent set of changes:

Bugs
  1. Fixed memory leak in Stream
  2. Fixed situation where a promise could be rejected and resolved at the same time via deferred
  3. Worked around problem with Java and CSharp where the macro "whenall" function would error out on array types for some reason.
Changes
  1. link functions are now instance rather than static (less code, slightly faster, but minor)
  2. use the new (faster!) asap library for browser/node js, which should fix some of the weird slowdowns in newer v8.
  3. added more thrown errors for states that I think need to be treated as such (treating a stream "end" state similar to a promise "rejected" state... disallowing continued resolutions)
  4. Macro monadic do forms are moved to MacroPromise and MacroStream, etc.
New Features:

Stream has a new abstract form that I've been experimenting with.  It treats the ">>" operator as the "then" method, and "||" as the "pipe" method.  I think it makes things look a bit neater, but thought I would get some feedback.

E.g.:

var p = new promhx.PublicStream<String>(); var s:AbstractStream<String> = p; var k = s >> function(x) { return x + ' foo';} >> function(x) { return x + ' bar';} || function(x) { trace(x); return new promhx.Stream<Int>();} $type(k);  // promhx.abs.AbstractPromise<Int>;
p.resolve("baz");
// traces: baz foo bar

I got this notion from Juraj IIRC, I think he's done something similar and might have a trip report.

The other option is to override basic math/concatenation operators for promises and streams, and then provide "deferred" versions of them automatically.

E.g.:

var s :AbstractStream<String> = new Stream<String>();

var k = s + 'a string';
$type(k); // promhx.abs.AbstractPromise<String>;






Chris D

unread,
Nov 29, 2015, 12:27:25 AM11/29/15
to Haxe
Nice work! 

About the syntax sugar, I'd rather see support for something more similar to async / await like in javascript es7 and C#. The keywords make their operation more clear, using || here is kind of confusing.

Justin Donaldson

unread,
Nov 29, 2015, 8:13:55 AM11/29/15
to Haxe
I suppose I'm biased, but I like promises/streams better.  
  1. They're fully non-blocking (this is mainly out of necessity, since some platforms like js can't block).
    1. as a corollary, they're guaranteed to resolve asynchronous, meaning you can continue to operate on them in the current loop (chain, set up pipes/then operations, error handlers etc.) without worrying about them actually operating immediately.
  2. They give more guarantees for special cases (promise can resolve only once, streams can end, etc)
  3. You can customize the event loop (or promhx will try to find the "best" one available on the given target)
If you try promhx for a while, I think you'll like them better as well!

Chris D

unread,
Nov 30, 2015, 3:03:28 AM11/30/15
to Haxe
Hi Justin I don't think your being biased, I was not suggesting async / await as some alternative to promises. Just async await keywords are an alternative to the syntax sugar of your example >> is a macro for 'then'... 

Please checkout some nice examples of async await in this post http://pouchdb.com/2015/03/05/taming-the-async-beast-with-es7.html

I see someone has already written some macro magic for callback like apis with async await in haxe https://github.com/Atry/haxe-continuation

Juraj Kirchheim

unread,
Nov 30, 2015, 9:00:02 AM11/30/15
to haxe...@googlegroups.com
On Sun, Nov 29, 2015 at 4:47 AM, Justin Donaldson <jdona...@gmail.com> wrote:
New Features:

Stream has a new abstract form that I've been experimenting with.  It treats the ">>" operator as the "then" method, and "||" as the "pipe" method.  I think it makes things look a bit neater, but thought I would get some feedback.

E.g.:

var p = new promhx.PublicStream<String>(); var s:AbstractStream<String> = p; var k = s >> function(x) { return x + ' foo';} >> function(x) { return x + ' bar';} || function(x) { trace(x); return new promhx.Stream<Int>();} $type(k);  // promhx.abs.AbstractPromise<Int>;
p.resolve("baz");
// traces: baz foo bar

I got this notion from Juraj IIRC, I think he's done something similar and might have a trip report.

Hey Justin. Yes, `>>` is how tink transforms futures. The advantage of operator overloading is that it makes the use of macros unnecessary, because you can define `>>` for both synchronous and asynchronous transformations and what not. I do occasionally use futures and signals in macros, so this was important for me. I added this over two years ago and I haven't run into any issues or heard any complaints, so it's fair to assume that it works ;)

Best,
Juraj

Sam MacPherson

unread,
Nov 30, 2015, 4:08:13 PM11/30/15
to Haxe
Digging the new macro syntax. Would it be possible to generate a warning or something if the return type of a then block is a Promise? I've hit this problem several times, and it's not easy to catch. Going all the way maybe the then and pipe can be merged like I suggested before using this new macro magic. :)

Justin Donaldson

unread,
Dec 1, 2015, 7:52:40 PM12/1/15
to Haxe
On Mon, Nov 30, 2015 at 3:08 PM, Sam MacPherson <xyl...@gmail.com> wrote:
Digging the new macro syntax. Would it be possible to generate a warning or something if the return type of a then block is a Promise? I've hit this problem several times, and it's not easy to catch. Going all the way maybe the then and pipe can be merged like I suggested before using this new macro magic. :)

Thanks man!

Here's the full spec, fwiw:

I think what you're proposing is to treat the "then" function like "pipe" if it detects that a promise is returned.  I think I can swing that, but I'm concerned it might introduce a lot of compilation overhead for the macro system.  

Furthermore, consider a function that wraps one or more arguments in an array.  Should it behave any differently if an array is passed in as an argument?  That is, should we make it impossible to return an Array<Array<T>>?  I think we should want that type of return, just like we should want Promise<Promise<T>>.



 

 

Sam MacPherson

unread,
Dec 1, 2015, 8:25:14 PM12/1/15
to Haxe
So my experience on this matter is coming from a fair bit of usage of the es6 Promise in JS. Promise.then() in es6 treats Promise returns the same as the Promise.pipe() from promhx. I have never personally, nor can I think of any practical use for returning a Promise from a chained function and intending to use the Promise object itself as the object to resolve. On the other hand when using promhx in practise I have encountered many times where I initially write a chained Promise.then() function to return a value then later refactor to return a Promise and it resolves immediately. Typing doesn't catch this because I am not interested in the return value, just that the Promise resolved.

I remember we had this conversation before about detecting this dynamically, but I agree this is kind of a weak solution. If it can be done with macros then this would be the best of both worlds IMO.

Chris D

unread,
Dec 1, 2015, 9:17:42 PM12/1/15
to Haxe
On the topic of es6 promises is there an existing example of wrapping an es6 promise api with promhx?
Would it be problematic to write externs for something like pouchdb (es6 promises) and use it with promhx?

Justin Donaldson

unread,
Dec 1, 2015, 11:20:07 PM12/1/15
to Haxe
On Tue, Dec 1, 2015 at 7:25 PM, Sam MacPherson <xyl...@gmail.com> wrote:
So my experience on this matter is coming from a fair bit of usage of the es6 Promise in JS. Promise.then() in es6 treats Promise returns the same as the Promise.pipe() from promhx. I have never personally, nor can I think of any practical use for returning a Promise from a chained function and intending to use the Promise object itself as the object to resolve.

I don't think this is a great argument in and of itself.  Providing consistent static types for return methods can help make the library more composable (e.g. the monadic "do" notation extensions that I provide out of the box).  It also  enables others to more easily provide compatible alternatives.  In other words, sometimes the practical purposes are not the developer, but rather the developer of some higher order library, or alternative implementation.

 
On the other hand when using promhx in practise I have encountered many times where I initially write a chained Promise.then() function to return a value then later refactor to return a Promise and it resolves immediately. Typing doesn't catch this because I am not interested in the return value, just that the Promise resolved.

Refactoring to return a promise should not resolve it immediately.  Maybe I'm misunderstanding your context.

I do want to make catching that kind of problem easier.  One thing that comes to mind is providing some form of timeout error for promises that never get resolved.  Are there other approaches that come to mind?

 

I remember we had this conversation before about detecting this dynamically, but I agree this is kind of a weak solution. If it can be done with macros then this would be the best of both worlds IMO.

Sorry for rehashing this, I thought it deserved a slightly larger audience.  I'll try out the macro approach and see what I can come up with.  It seems the best way to provide a happy medium at present.



Dion Whitehead Amago

unread,
Dec 2, 2015, 12:36:55 AM12/2/15
to Haxe
Feature request:

1) Capturing the location in code where a promise is created, so that stack traces are more useful. Perhaps this could be accomplished with macros?
2) Clearer syntax for 'resolving' streams. The PublicStream sort of does this with the 'update' method. Calling "resolve" on a Deferred bound to a stream feels misleading, since it's technically not resolving, since it's a stream, not a Promise. I think that's the result of building Streams and Promises from a shared codebase, when they're different things.

Keep up the great work!

Justin Donaldson

unread,
Dec 2, 2015, 10:44:48 AM12/2/15
to Haxe
On Tue, Dec 1, 2015 at 9:36 PM, Dion Whitehead Amago <dio...@gmail.com> wrote:
Feature request:

1) Capturing the location in code where a promise is created, so that stack traces are more useful. Perhaps this could be accomplished with macros?

It sounds like I need to invest more effort in "debuggability".  I'll try to expand the (admittedly primitive) debugging features.
 
2) Clearer syntax for 'resolving' streams. The PublicStream sort of does this with the 'update' method. Calling "resolve" on a Deferred bound to a stream feels misleading, since it's technically not resolving, since it's a stream, not a Promise. I think that's the result of building Streams and Promises from a shared codebase, when they're different things.

There's not a whole lot of meaningful difference.  Promises have some more constraints, and Streams have more utility methods (concat, filter, etc.) since they're more flexible.  Since they're both derived from the same underlying principles they work together really well... I think that's a big win.  

However, to keep the semantics clearer, I'll try changing deferred "resolve" to "set" or something more generic.

 

Keep up the great work!


Thanks!

 
Reply all
Reply to author
Forward
0 new messages