6 ms·
I don't see how this solves the "coloring" problem. "Colored" functions have a different return type; a future of some sort. If you want to return a future to a
by Rapzid 6y ago
I don't see how this solves the "coloring" problem. "Colored" functions have a different return type; a future of some sort. If you want to return a future to a caller, or have a method that blocks until the work is done, you still need a way to differentiate that.
Golang does essentially the same thing and uses channels instead of "futures". However, some APIs will have functions that return a channel that you receive a message on later.. Which is a lot like a future. And if you provide a more simple non-channel API along side(instead of making the consumer wrap your calls in a Go routine or always use a channel), you now have "colored" functions.
I believe this is just a solution to a scheduling problem(pre-emptive vs cooperative).
- chrisseaton 6y ago> "Colored" functions have a different return type; a future of some sort. This is an aside and possibly pedantic, but everyone seems to have forgotten that the whole idea of futures was originally that they weren't some different type. They were the same type, but blocked transparently on demand and had no `get` operation. The construct that came before futures, called eventual-values, had the different-type thing. The only difference of futures, the big idea, was they said 'maybe we can get rid of that part'. > These “futures” greatly resemble the “eventual values” of Hibbard’s Algol 68 [39]. The principal difference is that eventual values are declared as a separate data type, distinct from the type of the value they take on, whereas futures cannot be distinguished from the type of the value they take on. (Halstead, 1985) But now people write types like `Future[T]`... which completely misses the point! If you start to write `Future[...` then think to yourself... this isn't a future. And that's how you get this colouring problem you describe... it was already fixed and people have forgotten all about it.
- dfee 6y agoI don’t understand your final point. Are you saying that generics on futures are bad? I don’t see the alternative.
- chrisseaton 6y ago> Are you saying that generics on futures are bad? Yes - because it means existing code that expects a T cannot accept a Future<T>, which is the colouring problem being discussed. You end up with half your code accepting futures and the other legacy half not accepting them and there's a divide. If you want to use the legacy code you have to force the future potentially before you really needed it. > I don’t see the alternative. The alternative is wherever a function accepts a concrete value T t, also let it accept a future value T t. When t is actually used, then block as if get was called.
- tinco 6y agoDoes this mean that Rust's Future trait is incorrectly named? Or at least not named according to the academic use of the word? Of course because Rust's runtime or lack thereof aims to be zero overhead a Future could never be without the poll function.. right? You need a runtime to make regular functions accept these magic opaque future values.
- chrisseaton 6y agoYes not named according to the original paper. Yes it requires some kind of special compiler or runtime support.
- wbl 6y agoIsn't Future a functor?
- chrisseaton 6y agoThat's not the intention of the original authors, no.
- valenterry 6y ago> Yes - because it means existing code that expects a T cannot accept a Future<T> First of all, this is a programming language specific problem, not a general one. A good language allows you to write: someFuture.map(someFunction) Where "someFunction" accepts the plain value of type T that is stored within "someFuture". Yes, you cannot write someFunction(someFuture), but that is a good thing, since asynchronous execution can very well change the behaviour of the program. Hence, I want the compiler (if there is one) to warn me if a variable that I pass to a function is now a Future instead of a plain value. I then map over the Future and I'm good. Or, maybe I want to wait for completion of the future and I'm good. In both cases, there is no reason to write a second version of "someFunction". Therefore... > If you want to use the legacy code you have to force the future potentially before you really needed it. ... this is only true in incapable programming languages.
- LgWoodenBadger 6y agoThis seems a lot like the “remote calls are invisibly transparent” which most people decided was a bad idea. (IIRC)
- chrisseaton 6y agoI'm not debating if it's a bad idea or not - I'm just saying that's the definition of future as the authors intended it. If you don't want that that, then maybe call it an eventual value instead as you don't have the single essential part of what makes a future.
- valenterry 6y agoI think the general meaning of this term has changed. Future is now considered a different type and I think we just have to accept that the older definition isn't really used anymore.
- chrisseaton 6y agoYes and to be honest I've written Future<... myself.
- rdw 6y agoIt solves the coloring problem by not having a coloring problem in the first place. Maybe I should have said "avoids the function-coloring problem".
- Rapzid 6y agoI believe the example in the article "avoids the function-coloring problem" by completely avoiding its problem space of continuing the execution of an imperative block of code after starting an asynchronous task to produce some value, and then synchronizing at the production of that value. In the example each code block run in a fiber blocks at Net::HTTP.get and only continues after it returns a value. Looking at the API for Fiber.. It looks like "resume" returns the yield(generator) or fiber return value? So Fibers can be treated as a sort of Promise? As soon as you start returning fibers from methods you have the coloring problem..