In the latest CE 3 proposal, Daniel suggests we come up with a new name for ExitCase:
sealed trait ExitCase[+E, +A]
object ExitCase {
final case class Completed[+A](a: A) extends ExitCase[Nothing, A]
final case class Errored[+E](e: E) extends ExitCase[E, Nothing]
case object Canceled extends ExitCase[Nothing, Nothing]
}
Some ideas:
TerminationTerminatedEndA task that completes in error or is canceled, has not terminated by definition (from a type theory perspective this is the bottom type).
I feel that ExitCase is better than Termination, Terminated or End.
Also to my shame, I haven't completely reviewed the entire proposal yet, looking at the "new" type I have concerns, but I'll open a new issue for it.
A task that completes in error or is canceled, has not terminated by definition (from a type theory perspective this is the bottom type).
I disagree, as the context here is the language we use to talk about fibers, not PLT. How do we talk about fibers finishing their execution? Anecdotally, I see conversations like "first, fiber 1 terminated with an error, then fiber 2 completed, and finally, fiber 3 was canceled."
I'm just bike shedding — and I know naming things is hard — so if you feel that the current name needs to be changed, then fine, however consider ...
It depends on what the subject of the sentence is. I don't feel like fiber is a good subject to talk about, versus the task that was forked which is a much better subject.
What is a fiber anyway?
If we view it like a Thread (threads can also be joined or interrupted), then does it make sense to talk of threads, versus the tasks running on top of those threads?
Sure, it might help to develop a working mental model (linking to Wikipedia here, b/c I've read The Design of Everyday Things, a book that I loved and that explains this and I'm guessing that link might help to explain what a "mental model" is).
The problem with mental models is that they can be based on inaccurate or untrue implementation details that may change or that may not be useful depending on context. For example when "fibers" happened in this ecosystem, they were marketed as the best thing since sliced bread, yet in our implementation they are nothing more than a wrapped Future, as in a variable that gets completed once when processing is done, processing that first gets forked via a thread-pool execute, which may or may not involve a separate thread.
In other words the Fiber is nothing more than a delivery mechanism for a result that will happen asynchronously, an atomic variable that collects callbacks for as long as the result is not ready.
The result however, is not the result of the "fiber", but the result of the task that was forked. If you would do task.startAndForget, the task would still run, on a separate thread of execution, yet no actual "fiber" would be involved in that process.
If we're talking about mental model, a Fiber is a synchronous sequence of steps (which in turn is how I view a thread conceptually as well) that abstracts over an underlying async process.
That being said, I agree with the point that we should talk of the task instead, and I propose the name Outcome.
An IO[A] is a computation whose outcome is to either terminate with a value, fail with an exception, or never terminate/be interrupted.
Btw — I feel like giving it the name Fiber, a noun, was the wrong call. A much better name would have been an adjective like Forked.
So I'm going to admit that I liked Fiber more due to marketing reasons 🙂
Outcome isn't bad 🙂
Btw — I feel like giving it the name Fiber, a noun, was the wrong call. A much better name would have been an adjective like Forked.
Actually for us the runloop is the actual fiber (callstack that gets scheduled), and Fiber is really Handle (which you can use tojoin and cancel a runloop/fiber)
Actually for us the runloop is the actual fiber (callstack that gets scheduled), and Fiber is really Handle (which you can use tojoin and cancel a runloop/fiber)
Right. Making progress, we kick started the naming series well 😄
There's some fairly ancient literature which is relevant to this which used the term "workpile" for this sort of abstraction. See here for an example.
I dug into this pretty heavily during the NIO design process.
This might be a better link.
A Google Scholar search for "workpile" turns up quite a lot of useful stuff from the 90s.
Regarding mental models…
I had originally thought of "fiber" as just referring to the handle to the running computation, but I think it's actually a lot more useful as a more general term. Specifically, I think of it as a chain of bound sequential actions (which may be sync or async), which may be finite or infinite. So rather than referring to something like "bind chain" or "local run loop", which are somewhat implementation-dependent terms, I've been saying "fiber" even when talking about the outermost sequence. This seems relatively in line with how the term is often used throughout the rest of the ecosystem, so I'm pretty comfortable with it.
In other words, the following is a single "fiber":
object Foo extends IOApp {
def run(args: List[String]) = IO(println("hi")) >> IO(println("there"))
}
This is the main "fiber", despite the fact that it is never started or cancelled, and you can never get access to a Fiber instance which corresponds to it (nor should you, if you think about it, since this is the top-level execution).
Basically, my current use of the term "fiber" corresponds well to how most people use the term "thread" or "thread of execution" in lower level runtime usage, where the term is applied even when you're not explicitly manipulating Thread instances, and simply means a sequence of instructions. "Fiber" is distinct, as a term, since it's a sequence of instructions which may have suspension points, interrupt safe-points, resource management scoping, and may be frequently relocated to different native threads.
Really, a "fiber" is a green thread with resource management.
I still need to read @milessabin's links.
Anyway, to the OP point… The reason I don't like ExitCase so much is it, in its CE3 form, represents the fundamental algebra of an effect. A single effect may produce a value, it may error, or it may be canceled by some other fiber. The name EffectAlgebra is more descriptive and precise, though still a pretty horrible name. ExitCase just doesn't imply the concept very well.
Looping back to this… It seems like Outcome is the winner by default so far?
I really liked ExitCase in 2.0, but for 3.0 it does indeed lose some accuracy. I'd still target a similarly friendly name (unlike EffectAlgebra) - Outcome sounds quite good to me.
I'm good with Outcome.
Most helpful comment
Outcomeisn't bad 🙂