Okay, technically you are right - however it changes the semantics of the program. I admit that I didn't mention this constraint though.
> Great... but you've rewritten the library code with 'two separate functions instead of one.' My original point was 'because it means existing code that expects a T cannot accept a Future<T>' and you're proving that back to me so hard that you've accepted you need to completely rewrite the code to do it!
> Yes this is a problem with transparent futures, as is the ordering issue you raised. But I wasn't arguing they didn't have their own issues.
I don't disagree with any of that. However, what you originally said:
> > 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.
And you imply that transparent futures are better than the ones with generics. So where we disagree is on what is worse. I am convinced that the problems (and there are certainly a lot of unknowns) you introduce with transparent futures is much worse than the performance you might gain in certain cases and the easier syntax in many cases.
I believe it's important to expose the fact that an asynchronous(potentially parallel) task is doing something for you. The runtime semantics of an assignment would appear the same in code by be very different behind the scenes otherwise. Also, a lot of code is written to manage those tasks in use-case specific ways. How would you race or cancel transparent futures?
This is just not a true statement - and that was the point of the original thread - the original paper on futures had them implemented transparently and able to be passed down into library code not expecting futures. It's also how Haskell's par works today. So it demonstrably can be implemented.
> I believe that the user (at the callsite) should both _know_
Ok but this is just a 'don't do that' argument. If a user tells us they have a good reason to do it, I'm interested in how we can enable them to do that.
> with a library function that just expects 3 values, this is not possible
But it is in Haskell using par, and other languages with more traditional futures.
> Here is how I would write it
Great... but you've rewritten the library code with 'two separate functions instead of one.' My original point was 'because it means existing code that expects a T cannot accept a Future<T>' and you're proving that back to me so hard that you've accepted you need to completely rewrite the code to do it!
Languages with traditional futures would let you just call the original, unmodified library code, with future values instead of actual values, and it would just work.
If you had library code like this, you could pass in future values of T for a, b, and c, and it would execute the expensive_operation on a and b as soon as it could, while c completes.
> For instance, in your example: what happens if the library decides to always evaluate "c" eagerly even though "a" and "b" often fail and the whole calculation is aborted?Yes this is a problem with transparent futures, as is the ordering issue you raised. But I wasn't arguing they didn't have their own issues. You're saying it's impossible and that is demonstrably false, because languages do do it.
(I did half of my PhD on these topics, and the other half on Ruby.)