Vert.x and Promises

1,545 views
Skip to first unread message

Tom Carchrae

unread,
Oct 2, 2013, 1:03:57 PM10/2/13
to ve...@googlegroups.com
I've changed the thread name..

On Wed, Oct 2, 2013 at 1:57 AM, petermd <pet...@gmail.com> wrote:
Wondering if you've looked at RxJava at all? Offers similar power to Promises (has a lot more operations, which you may/may not consider a good thing..)

I did read a bit about RxJava but have not tried it.  I would say more is not better - but perhaps I haven't needed (or re-implemented) those ones yet! :)

I've seen Daryl's implementation and module, and also these chaps: https://github.com/englishtown/when.java who also did some work with when.js and vertx (there are fixes for vertx in the when.js project).  It was mentioned on this list but did not get much response - so I hope they were not discouraged by that. 

And there is my own version.  The thing I found when going from Javascript to Java was in finding the right level of generics to use.  My first implementation had a ton of them, but I backed down and now only have a single generic parameter on a promise (which is the resolved value) and the rejected value is a Throwable: https://gist.github.com/carchrae/6794509  (and yes, I'm still not sure if I think Throwable is the best default value for reject but I kind of liked it as a convention (eg, it can catch/handle all sorts of runtime errors) - otherwise, the reject value could be a second type parameter - I also realize this is not polyglot friendly).

I'm still giving some serious though to how much generics help with promises.  One of the nice things about the javascript promises/A+ API is that often a value or a promise can be substituted.  That pretty much flies in the face of generics; although the strictly typed hero would say, quick, create a class/interface called PromiseOrValue.

I was a Play 1.x user (and still am, and my current app is using both Vert.x and Play 1.x.  I built a pretty simple bridge between them).  In Play 1.x they had continuations and they were really cool, but did some awesome but dreadful bytecode magic to implement.  I watched as Play 2.x went down the lambda rabbit hole.  There are a lot of similarities to the async emphasis and vertx. 

I was a full time Haskell programmer for 4 years (in the 90s), and I find the use of functional constructs has been over-zealously applied to async web coding in the past few years.  Play 2.x does this a lot, and it is one of my biggest criticisms of Scala - people using map just because they can, when a more imperative construct would make the code easier to read.  Just my opinion of course... :)


the equivalent implementation for the problem you mention would be something like

// Request parser (you might parse to a strongly typed request object or just Json)
Func1<HttpServerRequest,JsonObject> requestParser=new Func1() ...

// Re-usable auth handler (can be async so can contact a remote service / DB) that validates any business request object (Http or EventBus)
Func1<JsonObject,Observable<JsonObject>> messageAuth=new Func1() ...

// HTTP Handler

return
  Observable
    .just(httpRequest)
    // Parse to JSON
    .map(requestParser)
    // Validate auth
    .flatMap(messageAuth)
    // Process the request
    .flatMap(new Func1<JsonObject,Observable<JsonObject>) {
      public Observable<JsonObject> call(JsonObject req) {
        // Use a DB wrapper to decode errors / help generate requests etc
        return db
          .find(...DB operation based on req...)
          // Convert the successful response to appropriate JSON
          .map(decodeResponse);
      }
    });

The output of every service is an Observable<JsonObject> that I encode into a HttpServerResponse for Http clients, or a Message.reply() for EventBus etc etc


I don't find this sample as clear as the Promise/A+ API.  It could look like this:

 checkAuth(req)
   .then(doDataBaseOperation(req),sendAuthDenied(req))
   .then(sendResult(req));

For the uninitiated, the syntax for then is:  then(onFulfilled,onRejected) - and implementations like when.js (or when.java) add some syntax sugar to make this clearer.  

Tom







 

Mikael Karon

unread,
Oct 2, 2013, 1:39:10 PM10/2/13
to ve...@googlegroups.com
Don't worry, we're not discouraged. We picked an implementation of promises as similar to promises/a+ because we already have a few front-end teams that use js promises in their products and its been a great fit for handling async (actually, we went down the path of jQuery deferred first but we've since converted).

We agree with you that less is more, and its nice when you have java developers talking to js developers to get their async code organized (js ppl have had to deal with async and callback hell for a bit longer, so there's probably some mines one can avoid to step on simply by learning from their mistakes)

We also looked at rx-java in the beginning but we feel it really forces the developer to adopt an entirely new way of solving a problem where help with managing async was all they really wanted (not saying that a new way is bad, but its hard enough to get someone that is used to sync to really understand async without any more 'noise' added). 

Plus, our plan here is that the teams that are now doing front-end can put together quick prototypes for back-end services in the future (still in js) and where needed we can port these to java. Having the same async patterns in both places really simplifies this.

/ Mike
--
You received this message because you are subscribed to the Google Groups "vert.x" group.
To unsubscribe from this group and stop receiving emails from it, send an email to vertx+un...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Tom Carchrae

unread,
Oct 2, 2013, 2:26:25 PM10/2/13
to ve...@googlegroups.com
That totally makes sense Mike.  I'm working on the same general principle of being able to use the same API for logic code so it can easily move from client to server.  However, I'm writing Java code that passes into Javascript via GWT - the callbacks work perfectly (so far) from when.js and all my logic code is Java.  

Anyway, thanks for sharing your implementations!  I'll see how mine progresses, and/or look at how they all fit together.  

I also wanted to mention this Promises implementation: https://github.com/tbroyer/promises  - Thomas Broyer is a fantastic programmer and really active in the GWT world - although the project I just linked to is not GWT code, it runs with Guava constructs.

Tom



Christian Vogel

unread,
Oct 2, 2013, 5:36:42 PM10/2/13
to ve...@googlegroups.com, t...@carchrae.net
Hi Tom,

Seems many people are looking for a nice promises/observable method :-) 

I've also worked on something, using the XTend language (a kind of Coffeescript for Java). I like RXJava for its completeness and of course it is a well-tested library. However creating observables is a pain. After a lot of fiddling I've been able to abstract creating them in a similar way that Reactive Java does it. They use a Deferred<T>, I named it a (observable) Steam<T> but the concept is similar. Some (Xtend) example code:

val stream = Integer.stream


stream.listen

.take(2)

.map [ 'got number ' + it ]

.subscribe [ println('a: ' + it) ]


stream => [

apply(2.some)

apply(5.some)

apply(3.some)

apply(none)

]


The above code will print twice the number it got. Bit arbitrary but you see how it works. 

What might need some explanation is the Integer.stream. This is an extension, what actually happens is a call to stream(class<T> cls) { return new Stream<T> }. The apply(none) at the end is optional, but it communicates that there is nothing left. What is actually being pushed into the stream are optional types: a Some<T>, a None<T> or an Error<T>. This allows you to listen to values, be signalled the stream ended, or send an error. This type is not specific to Stream<T> by the way.

With this class, it is now easy to extend the Vertx EventBus:

def static <T> Observable<Message<T>> register(EventBus bus, String address, Class<T> msgType) {

val stream = new Stream<Message<T>>

bus.registerHandler(address) [ Message<T> it | stream.apply(it.option) ]

stream.listen

}

def static <T> Observable<Message<T>> register(EventBus bus, String address, Class<T> msgType, Procedure1<AsyncResult<Void>> onComplete) {

val stream = new Stream<Message<T>>

bus.registerHandler(address, [ Message<T> it | stream.apply(it.option) ], onComplete)

stream.listen

}


This then allows you to do this:

vertx.eventBus

.register('some/address', String)

.subscribe [

info('''got message «it.body»!''')

reply('thank you, got it')

]


Perhaps it will give you some ideas for your library as well!

Christian

Tom Carchrae

unread,
Oct 2, 2013, 7:31:58 PM10/2/13
to Christian Vogel, ve...@googlegroups.com
Hi Christian,

I had the exact same thought of using the vertx eventbus to manage promise resolution.  Not a new idea really, since that is how Javascript does it (on an event bus).  

The only difference in implementation from what Christian posted is

1) A promise is only resolved once, and only once.  Not twice, not thrice, nay, nor a dozen.  Yes, you can try, but the first value it resolves to never changes.

2) If a promise is resolved before you reference it, you get the value back.  Or in other words, a promise can be 'kept' before it is 'given'.

IMHO, those two points are why promises are so valuable to async programming.  

It seems straightforward enough to construct that around the eventbus, similar to your implementation of Stream, but with the two above rules in place (and you surely can't call it Stream anymore. ;) ) .  No need for bytecode injection, etc.  This is only about flow of control.  I don't think you need bytecode magic/continuations to make this really useful/powerful.

Tom






Christian Vogel

unread,
Oct 2, 2013, 7:42:10 PM10/2/13
to Tom Carchrae, ve...@googlegroups.com

Hi Tom,


Doesn't RXJava already support creating an observable from a Promise? I think it behaves just as you describe.


The reason I created a stream is that it is pretty cumbersome (IMO) to create a new observable from a handler, so I built a intermediary concept that allows this.


However you could use the same approach for a Future/Promise, and actually that is also how Reactor solves it:


https://github.com/reactor/reactor/wiki/Promises


In my case, I did it like this, works like the stream:


// create the future:

val promise = Integer.promise


// put something into it directly if you like

// promise.apply(3)


// observe the future by calling listen on it:

promise.listen

.map [ …] // do some mapping, take, etc

.subscribe [ println('found value ' + it) ]


// put something into it

promise.apply(12)

promise.apply(2) // throws an error, can only apply once


The term promise is used to avoid confusion with the Java Future class, which has a somewhat different interface. However, a Promise can be cast into a Future.


Christian


Christian Vogel
Nine Connections

Christian Vogel

unread,
Oct 2, 2013, 7:46:02 PM10/2/13
to Tom Carchrae, ve...@googlegroups.com

note, I made Promise<T> and Stream<T> both implement Procedure1<T>. This allows you to pass them as any other function.


Christian Vogel
Nine Connections

Tim Fox

unread,
Oct 3, 2013, 4:22:42 AM10/3/13
to ve...@googlegroups.com
On 02/10/13 18:03, Tom Carchrae wrote:
I've changed the thread name..

On Wed, Oct 2, 2013 at 1:57 AM, petermd <pet...@gmail.com> wrote:
Wondering if you've looked at RxJava at all? Offers similar power to Promises (has a lot more operations, which you may/may not consider a good thing..)

I did read a bit about RxJava but have not tried it.  I would say more is not better - but perhaps I haven't needed (or re-implemented) those ones yet! :)

I think the fundamental difference between an Rx approach and a promises approach is that promises deal with a single result, but Rx extends this to a stream of results. This makes Rx really useful for asynchronous operations involving streams of data, e.g. TCP, HTTP, file system, streaming, etc.

If you're not interested in that kind of thing then straightforward promises might be enough.



I've seen Daryl's implementation and module, and also these chaps: https://github.com/englishtown/when.java who also did some work with when.js and vertx (there are fixes for vertx in the when.js project).  It was mentioned on this list but did not get much response - so I hope they were not discouraged by that. 

And there is my own version.  The thing I found when going from Javascript to Java was in finding the right level of generics to use.  My first implementation had a ton of them, but I backed down and now only have a single generic parameter on a promise (which is the resolved value) and the rejected value is a Throwable: https://gist.github.com/carchrae/6794509  (and yes, I'm still not sure if I think Throwable is the best default value for reject but I kind of liked it as a convention (eg, it can catch/handle all sorts of runtime errors) - otherwise, the reject value could be a second type parameter - I also realize this is not polyglot friendly).

I'm still giving some serious though to how much generics help with promises.  One of the nice things about the javascript promises/A+ API is that often a value or a promise can be substituted.  That pretty much flies in the face of generics; although the strictly typed hero would say, quick, create a class/interface called PromiseOrValue.

I was a Play 1.x user (and still am, and my current app is using both Vert.x and Play 1.x.  I built a pretty simple bridge between them).  In Play 1.x they had continuations and they were really cool, but did some awesome but dreadful bytecode magic to implement.

I looked in detail about implementing continuations in Vert.x some time back and rejected the idea. Continuations are very hard to implement effectively on the JVM as the stack is not exposed and manipulatable at the byte code level, this means you have to have to horrible stuff like CPS transformations to transform the code to make it work. CPS transformations get difficult (impossible?) to perform when there are dynamic languages on the stack, reflection or third party libraries.

And even if you manage to CPS transform stuff you've basically re-invented threads, i.e. you need to keep track of your position, which means memory overhead - just like OS threads, and getting away from many threads with their memory overhead is one the reasons for going async in the first place.

I think most async frameworks (e.g. node.js, play) have dabbled with continuations but decided against them (play) or they never really got popular (node).

petermd

unread,
Oct 3, 2013, 5:42:25 AM10/3/13
to ve...@googlegroups.com
Rx is definitely designed for streams rather then invididual events which can make it seem a bit unwieldy for single operations. That said, the stream can be the processing flow for a complex operation rather then a data stream eg using the merge() and zip() operations to do parallel operations rather then just a sequential flow

Observable.just(req)
.flapMap(checkAuth)
.merge(updateDB(req),updateIndex(req))
.subscribe(nop(),sendError(req),sendResult(req))

@Tom - thanks for the insight. of course wrt to the sample code you could write the RxJava code pretty much identically (by just moving all logic to Functions).

One Q. Typically there would be no inline error handling ie (sendAuthDenied(req)) and you would just have .then(sendResult(req),sendError(req)) to handle all error paths (incl DB errors) and map to the HTTP Response? I assume Promise allows this also?

FYI mod-rxvertx also has a class called MemoizeHandler that provides an Observable that implements the same semantic @Tom mentioned (memoizes the handler result (once only)) and returns it to all subscribers even if they subscribe after the event) - used to implement a lot of the API wrapper. There are also implementations for AsyncResult etc

-Peter

Tom Carchrae

unread,
Oct 3, 2013, 12:46:36 PM10/3/13
to ve...@googlegroups.com
On Thu, Oct 3, 2013 at 1:22 AM, Tim Fox <timv...@gmail.com> wrote:
I looked in detail about implementing continuations in Vert.x some time back and rejected the idea. Continuations are very hard to implement effectively on the JVM

Play's version of continuations was always biting you in the ass with some strange side effect of stack manipulation; I love a bit of black magic reflection and 'that is crazy - you totally broke all the rules of the language', but it often has surprises.  You've probably seen it, but this was Play 1.x's hack: https://github.com/playframework/play1/blob/10ec9299125471b43ca7da17b14f31736d274626/framework/src/play/mvc/Controller.java#L919

BUT... you don't need any of that voodoo to implement non-thread locking promises in vertx.  I think the lack of thread locking is what I like, perhaps love, the most about vertx.  You side-stepped a massive can of worms in promoting a programming style that does not block threads - most of us buy the idea that thread blocking is a really bad thing to do if you want to build very fast systems.

It seems most of these other implementations *presume* you want to be able to wait on a thread or promise - which is why they are hard in the JVM.  In vertx, we just wait on an eventbus message.  Just follow the javascript route to implementing it (via an event bus), and that pain is gone.  

RxJava sounds interesting, but I'm not sure it scratches my itch for promises-style async coding.  I don't actually want any thread blocking magic.  Part of that is because, like what Mike is trying to do, I want to stick with a single thread coding model.  My big audacious goal is to build business logic and optimization algorithms that can run either on the browser or server - and the event loop model works really well for that.

Tom






Daryl Teo

unread,
Oct 3, 2013, 11:51:59 PM10/3/13
to ve...@googlegroups.com, t...@carchrae.net
I'd just like to mention that my Promises library 

 - is built on RxJava and is interoperable with my impl (to a certain extent, waiting for them to sort out their language jars)
 - supports Generics, type-inference, and also supports the delaying of promises via a secondary promise, which is also type-inference.

So, if you are either returning a promise or a value, you should return a promise, and immediately fulfill it with the value. Not that hard.

I'm also in concurrence with most of the views here: Reactive Programming and Promises solve fundamentally different problems. Just because 1 could be used to solve the other doesn't mean it should be used if it introduces too much weight.

Regards,
Daryl
Reply all
Reply to author
Forward
0 new messages