-
Notifications
You must be signed in to change notification settings - Fork 601
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Blocking terminology #1097
Comments
Thanks for the feedback @backuitist! I tend to agree that use of "blocking" throughout FS2 documentation is confusing for folks working on the JVM. At the very least, I think we should commit to never mentioning "blocking" without the "semantic" modifier. I'm open to other names too, though I don't like |
Do the other uses differ in semantic? |
Yes, they do. |
Wouldn't you say that you're "suspending a side effect" by suspending a computation? In other words, suspending a side effect is a by-product of suspending a computation. My impression is that it is widely understood that:
Examples of this are:
On the other hand, I can't find that many references of "suspending side effects" or "semantically blocking" in the literature, but I'm happy to be proven wrong :) |
No, these mean two different things. I agree that "suspend" is often used in the context of coroutines: it's not a bad name, it's just that we already use it everywhere in cats/cats-effect to describe the difference between say, IO and Future. On the other hand,
But the crucial difference is between having the blocked computation unable to do anything, and having the underlying system thread be unable to do anything. For example, in Haskell you talk about thread blocking liberally, even though it's only the underlying haskell thread that's semantically blocked, and not the OS thread. Note that for us, semantically blocking a thread is a closer description than a coroutine, from a user perspective the computation is just blocked until someone else unblocks it (see the scaladoc for Promise). We add I agree that the term is confusing and I'm open to changing it, but In the meantime, if you spot places where we use "blocking" without "semantically", PR's welcome :) |
The
I understand that In the Async SIP It seems that PS: your previous comment is missing the "crucial difference" but I can imagine that you wanted to illustrate how Future breaks the referential transparency. |
I pressed
I think we are talking about different things. when you do a
I don't understand this. If you are talking about suspend as in suspending side effects, IO does and Future doesn't, so they're not similar. If you are talking about submitting things to a Thread pool, Future does and IO doesn't, so they are also not similar. Also, if you say that Future suspends a computation (and I don't precisely know what you mean), then we still can't use it as a synonym of |
I'm talking about control. When a Future Well, I believe I've said enough about this :) so feel free to do whatever with it, but as you're mostly targeting the JVM you should understand that adding a foreign/non-standard terminology does not help with the already steep learning curve. Again I'd love to read proof backing your claims. |
If you are talking about However, your use of Furthermore,
Is not actually necessarily true. All a Future does is submitting a Runnable to a threadpool. If the threadpool has only one thread, and the Runnable blocks the thread, than the previous Future is blocked as well. |
As for the suspending effects, you are not going to find similar terminology, because Scala is the only language that does purely functional programming but isn't pure. |
Man, I hoped I wouldn't get an answer on a Saturday ;)
I never claimed otherwise. You misread my comment about You mean:
I mean
You meant if the "threadpool" (= This is what is expected from
In the language, but not in its implementation. Beside, I'm open to non-haskell papers. I find hard to believe that there isn't a standard terminology around effects. |
for {
a <- x.get // blocking
b <- y(a) // blocked by the line above
} yield b
val a = x.get // suspend
println("hello") // executed immediately after Right, that's it actually. Your interpretation is not very helpful in a pure context, because IOs are just values, nothing is happening, and they have no side effects, just like returning def kill = IO(killJVM)
kill
println("still here") Doesn't do anything, but if I'm writing docs for val a = x.get
println("hello") prints "hello" has nothing to do with promise, blocking, or threads, but just with the general fact that IOs are values, but in docs for for {
a <- x.get // blocking
b <- y(a) // blocked by the line above
} yield b holds.
It's also how Javascript behaves, and the reason why things that actually block a thread (like
Side effects, not effects. You might find it hard to believe, but:
My point isn't so much that your alternative words (like |
The implementation there is completely different. Haskell has lazy evaluation, so the problem there is not so much having to suspend the side effects (they already "suspended" by full laziness), but having to constrain evaluation so that things are evaluated in the correct order, and not shared between computations like normal lazy values are (this is what Haskell's IO, based on a fake state monad with In Scala we have the opposite problem. |
I'm now unclear on what aspect do you want us to change :) Is it that: for {
a <- x.get // blocking
b <- y(a) // blocked by the line above
} yield b doesn't block a thread, but only awaits semantically? (which is what we mean by semantic blocking) or that val a = x.get
println("hello") Doesn't do anything? I think the latter is equivalent to wanting us to document the side effects of Again, I'm open to changing the former, but not with |
I think we got a bit sidetracked here :) My example of It doesn't hurt my eyes to have for {
a <- promise.get // suspend the evaluation until the promise is fulfilled
b <- somethingElse(a)
} yield b Anyway, it doesn't seem that cats-effect will change its terminology, making my point here moot. |
Thank you for yours. If you can come up with another name for it, feel free to reopen :) |
I have in fact another name, Just kidding :) fs2 is great, thanks for the work ;) |
I find confusing the use of
blocking
throughout the documentation.I would argue that the generally accepted definition of blocking means that a thread is waiting for some event. As we know, a thread might be something different depending on the runtime.
In my eyes FS2 provides an environment in which "blocking" is cheap (like blocking a green thread), by means of continuations. Only that the underlying runtime isn't made of green thread, so blocking isn't the appropriate term, leading to the creation of a new term: semantically blocking.
As an FS2 user, working on the JVM I need to make conscious execution decisions (choosing an appropriate thread pool) depending on what kind of computation I'm dealing with (blocking or non-blocking). I believe that a semantically blocking operation is a foreign concept to most people working on the JVM, and documentation such as https://github.com/functional-streams-for-scala/fs2/blob/7ad702a21e4af95e188cff9a7352ff3bc17beabd/core/shared/src/main/scala/fs2/async/Promise.scala#L21 is confusing at best.
I'm therefore suggesting a different terminology: suspend.
The text was updated successfully, but these errors were encountered: