Closed alexandru closed 7 years ago
Name wise, I'm on board with Suspendable
or Deferrable
or some variant.
I don't think Sync
and Async
should have a subtype relationship though. Note in FS2, the subtype relationship exists but inverted -- Suspendable >: Async
.
I don't want a subtype relationship either, that was to illustrate a point.
As a prefix, the signature of async
can indeed be derived from delay
, and it can be done in two different ways that both agree: strong CPS transformation (Steele and Sussman), and classical Curry-Howard Isomorphism. Well, rather I should say that the signature of async can almost be derived in these ways. Both methods generate the following signature:
def delay[A](thunk: => A): F[A]
def asyncIsh[A](k: (A => Nothing) => Nothing): F[A]
It's not hard to convince yourself that these two signatures are equivalent. However, we want async
to provide more than just delay
, since we want users of the signature to have the freedom to thread shift without throwing exceptions, which is something that the strict derivation directly rules out. Thus, we flip the booleans on the return types, producing ((Either[Throwable, A] => Unit) => Unit) => F[A]
.
So there is in fact an equivalence, just a modified one in the interest of use-cases.
I'm not married to the Sync
name, but the primary reason I chose it (over Suspendable
or similar) is to highlight this relationship. Also, both typeclasses are in the effect
package, and so there's some precedent for this sort of thing (see: cats.functor.Invariant
).
thee Sync type-class has nothing to do with synchronous execution ... in case of IO, the created instances might as well execute asynchronously, you never know, because IO is async
I think we need to be very clear about some terminology here. When I say "synchronous", I mean a computation which occupies and at least one stack frame and opaquely executes to completion, producing a result or an error. When I say "asynchronous", I mean a computation which is scheduled and may or may not have an active running state, and also may or may not eventually produce a result without holding a stack frame. Synchronous computations, by definition, consume at least one thread during their evaluation. They cannot be evaluated in any other way. Asynchronous computations are differentiated because they do not have this restriction (this is what converting the Nothing
s to Unit
s buys us).
By these definitions, delay
is in fact the very definition of synchronous computation. It cannot be asynchronous, because it's going to hold a thread from start-to-finish of its computation. Now, that thread may not be the "main" one, but that speaks to parallelism, not to asynchrony.
And so Sync
defines the suspension of synchronous effects, to the same extend that Async
defines the suspension of asynchronous effects. We define Effect
to be the union of those two capabilities, together with the ability to asynchronously run as a side-effect (i.e. into IO
).
Again, not married to the name, but this was the rationale for choosing it.
@djspiewak I see.
Well, the naming is a little confusing to me as in my mind that name refers to something different and I'm thinking it will be confusing to other people. I guess the problem there is that by Async
, I'm actually thinking of Effect
, i.e. something that has an extract with an (A => Unit) => Unit
signature.
If I'm the only one that has a problem with Sync
, then you can ignore this proposal.
If I'm the only one that has a problem with Sync, then you can ignore this proposal.
As I recall, @mpilquist wasn't fond of the name either. :-) Let's get a little more input here.
Can we reach a conclusion here?
Here's evidence that Sync
will generate some confusion: April 24, 2017 11:46 PM 😏
Can we reach a conclusion here?
I want to hear from the other contributors as well. If we don't hear more opinions by end-of-week, I'll just make a decision.
Here's evidence that Sync will generate some confusion
I would argue that is evidence that people in general don't understand the distinction between "asynchronous" and "concurrent" (note the later characterization of Future
). If anything, I would expect that Sync
rather than Deferable
(or similar) would help progress the community towards a better mental model of these terms. That's not to say Deferable
is a misleading name, but rather Sync
drives home the distinction with far greater precision.
So if you care that much for Sync
and others don't chip in, I'm not going to fight it 😃
At least it's short, so that's a plus and the way you defined Async
it kind of makes some sense.
Alright, we're going to stick with the status quo for now. If this comes up again in the future though, we can revisit the decision.
Asynchronous versus Synchronous refers to the execution model and Asynchronous execution subsumes Synchronous execution as well.
We know that the
Async
type class has an async evaluation model because it's being set in stone by theregister
signature in itsasync
function. Implementations are free to execute stuff immediately / synchronously of course.Which is why
Sync <: Async
.So problems with the current naming:
Sync
type-class has nothing to do with synchronous execution ... in case ofIO
, the created instances might as well execute asynchronously, you never know, becauseIO
is asyncSync <: Async
relationship, no equivalence, no dualityTo put things in perspective, an actual
Sync
type-class is theComonad
.Alternatives:
Suspendable
Deferrable
Deferred