Raul, Yes, my design is an attempt to address exactly the problems you've mentioned (get rid of state, better type safety, cleaner code). I'm not an expert in reactive streams, but I believe Future is the most low level feature possible here, so higher level abstractions can be build using it.
Sergi 2015-10-13 19:32 GMT+03:00 Dmitriy Setrakyan <[email protected]>: > On Tue, Oct 13, 2015 at 9:19 AM, Raul Kripalani <[email protected]> wrote: > > > I like this approach. > > > > To me, the current API is messy and hacky, and even "spiritually" > > contradictory, may I say. The whole raison d'être of the current approach > > seems to be to achieve parity of APIs of IgniteCompute, IgniteMessaging, > > etc. in sync and async modes. However, truth of the matter is that we > only > > end up honouring half of the API in async mode: the method entry point > and > > parameters. The method return type is basically ignored, because all > > methods in async mode return null since the "virtual" return type is now > a > > Future that the user must obtain with a separate code. To me, this is a > > code smell. > > > > Moreover, I would argue that keeping a state (even if in a ThreadLocal) > > also makes certain use cases impossible or buggy, like Nikita > illustrated, > > e.g. passing IgniteCache, IgniteCompute, etc down the stack. > > > > In fact, keeping a state in async mode and not in sync is problematic > > because – to the eyes of the user – they're always interacting with the > > neutral interfaces IgniteCompute, IgniteCache, etc. They have no > indication > > of when a state is being kept and when not – only through documentation, > > common sense and human memory – something that's error-prone. > > > > Obviously the verbosity and fluency of user's code is also a factor to > > consider, but to me it is secondary. The above points are enough to > > advocate changing the async APIs. > > > > Finally, looking to the future, the current approach does make Ignite > > difficult to integrate with Reactive Streams. So it's great we're > > discussing it. > > > > @Sergey, the approach you propose would entail adding Async interface > > variants for each functionality. This is a step in the opposite direction > > of the spirit of the current API, am I correct? Since this is a change in > > direction, I would like for most of the team to approve or disapprove. > > > > I personally like Sergey's design. I actually don't see it as a step in the > opposite direction. I think it achieves the same goal, but in a much > cleaner fashion. Moreover, it seems to be .NET-friendly as well. > > > > > > Regards, > > > > *Raúl Kripalani* > > PMC & Committer @ Apache Ignite, Apache Camel | Integration, Big Data and > > Messaging Engineer > > http://about.me/raulkripalani | http://www.linkedin.com/in/raulkripalani > > http://blog.raulkr.net | twitter: @raulvk > > > > On Mon, Oct 12, 2015 at 5:53 PM, Sergi Vladykin < > [email protected]> > > wrote: > > > > > In my view we should not pollute sync APIs with all async methods, > > > definitely we have to separate them > > > for better UX. > > > > > > Currently on Java we have IgniteAsyncSupport with method withAsync() > > which > > > returns the same sync API > > > but that API works in broken manner. Instead it should look like the > > > following IMO > > > > > > interface AsyncSupport<X> { > > > X async(); > > > } > > > > > > Where X will be an interface with respective async API. For example > for > > > IngneCache we will have AsyncCache > > > with all the respective async variants of all methods. Like this > > > > > > interface IgniteCache<K,V> extends AsyncSupport<AsyncCache<K,V>> { > > > V get(K key); > > > } > > > > > > > > > interface AsyncCache<K,V> { > > > IgniteFuture<V> get(K key); > > > } > > > > > > From implementation standpoint both interfaces can be implemented by > the > > > same class but for user API > > > they will be conveniently separated. Implementation of every sync > method > > is > > > trivial if we have > > > async counterpart: just call get() on received future. > > > > > > From documentation point of view we just have to write on each method > > that > > > it is a async variant of some > > > method on main API like following: > > > > > > /** > > > * Asynchronous variant of method {@link IgniteCache#get(Object)}. > > > */ > > > > > > This way we will not need to maintain the same docs for all sync and > > async > > > methods. > > > > > > Sorry, I'm not an expert in .Net but I believe this approach will fit > > .Net > > > as well, so it can be consistent across platforms. > > > > > > Sergi > > > > > > > > > > > > 2015-10-12 19:10 GMT+03:00 Dmitriy Setrakyan <[email protected]>: > > > > > > > Do I understand correctly that you are suggesting adding "Async(..)" > > > > counterparts for all the synchronous methods? > > > > > > > > Are there any objections about this? If we do it in .NET, then we > might > > > as > > > > well do it in Java, because in my view the same reasoning can be made > > for > > > > Java. This will cause significant proliferation of Async methods. For > > > > example just on IgniteCache API, we will have to add about 40 Async() > > > > methods. > > > > > > > > D. > > > > > > > > > > > > > > > > On Mon, Oct 12, 2015 at 3:45 AM, Vladimir Ozerov < > [email protected] > > > > > > > wrote: > > > > > > > > > No. "await" is actually return from the method immediately. Let me > > show > > > > it > > > > > again: > > > > > > > > > > async Task<int> GetAndMultiply() { > > > > > Task<int> res = cache.GetAsync(1); > > > > > > > > > > await res; > > > > > > > > > > return res.Result * res.Result; > > > > > } > > > > > > > > > > maps to the following pseudo-code in Java: > > > > > > > > > > Future<Integer> getAndMultiply() { > > > > > Future<Integer> res = cache.getAsync(1); > > > > > > > > > > return res.chain((f) => { > > > > > return f.get() * f.get(); > > > > > }); > > > > > } > > > > > > > > > > > > > > > > > > > > On Mon, Oct 12, 2015 at 1:36 PM, Yakov Zhdanov < > [email protected]> > > > > > wrote: > > > > > > > > > > > Is current thread blocked until "await" instruction is completed > in > > > > > > parallel thread? > > > > > > > > > > > > --Yakov > > > > > > > > > > > > 2015-10-12 10:41 GMT+03:00 Vladimir Ozerov <[email protected] > >: > > > > > > > > > > > > > Example with Get() operation: > > > > > > > > > > > > > > async Task<int> GetAndMultiply() { > > > > > > > // This line is executed in current thread. > > > > > > > Task<int> res = cache.GetAsync(1); > > > > > > > > > > > > > > await res; > > > > > > > > > > > > > > // This code is executed in another thread when res is > ready. > > > > > > > int mul = res.Result * res.Result; > > > > > > > > > > > > > > return mul; > > > > > > > } > > > > > > > > > > > > > > On Mon, Oct 12, 2015 at 10:12 AM, Dmitriy Setrakyan < > > > > > > [email protected] > > > > > > > > > > > > > > > wrote: > > > > > > > > > > > > > > > On Sun, Oct 11, 2015 at 3:42 AM, Vladimir Ozerov < > > > > > [email protected] > > > > > > > > > > > > > > > wrote: > > > > > > > > > > > > > > > > > Guys, let's try keeping this topic focused on .Net please, > > > > because > > > > > > the > > > > > > > > > product is not released yet and we can create any API we > > like. > > > > > > > > > > > > > > > > > > Dima, answering your question about async/await - this is > > > > actually > > > > > > > native > > > > > > > > > continuation support in .Net. Consider the following .Net > > > method: > > > > > > > > > > > > > > > > > > async void PutAndPrint() { > > > > > > > > > await cache.PutAsync(1, 1); > > > > > > > > > > > > > > > > > > Console.WriteLine("Put value to cache."); > > > > > > > > > } > > > > > > > > > > > > > > > > > > > > > > > > > And what if the method putAsync would return a value. How > would > > > > this > > > > > > code > > > > > > > > change? > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > >
