Support ticket #39482: "The programming language is nice, but if it hadn't been for that piece of shit debugger, I'd have been married a long time ago..."
One of my favorite implementations of comefrom is in threaded interval. Multiple comefroms from the same target are treated as a fork and is the only way to create a new thread. The only way the new threads can communicate is by disabling statements.
Think about it: When you inject a dependency (say Java spring @Autowired), then you are asking spring to run all sort of code, at the point where it injects your variable with autowired.
Spring needs to instantiate your requested object, and everything that it depends on - it might be a lot of code.
Jokes aside, another possible use is to implement an internal cooperative multi-tasking similar to that used in Windows 3.x and classic Mac OS. If I remember correctly, long running tasks in Windows had to pepper their code with calls to yield() in order to be good Windows citizens, similar to label X when using COMEFROM X.
This is a bit of a stretch. The way cooperative systems worked is that blocking or long-running calls tended to yield. Most of the time the explicit yields therefore weren't needed, you could just wait until the next blocking call.
You could replace the cooperative system with preemption and most people wouldn't notice the difference. That's exactly what Win32 did, the programming model and APIs were largely philosophically the same.
Today's preemptive multitasking systems also sometimes call the scheduler on syscalls, effectively doing the same as those cooperative systems did. And eg. Linux has sched_yield. It's pretty common even today to see that wherever you have something close to a busy loop.
Win16 programs just called GetMessage() in a loop. If there was a message for that window proc, then that call returned and once it did, that window proc had the CPU - and nothing could preempt it. Nothing else in the system would get CPU time unless that window proc completed its activity and looped back to call GetMessage() again, or alternatively, calls yeild(). That's it. Yield() was intended to be used where the window proc needed to do something long running, thus giving other processes a chance to process their window messages.
> You could replace the cooperative system with preemption and most people wouldn't notice the difference.
Oh yes we did notice! I beta-tested several MS OSes (Win3.0, Win3.1, WfW3.11, Win95, NT3.0, Win98). The difference between the cooperative multitasking on Win16 and the preemptive multitasking on Win32 was like chalk and cheese! Before that, a single misbehaving app could hang your entire system at any time. Needed a hard reset or power cycle. At least with Win9x, it took a misbehaving driver to hang your PC. A misbehaving app would (usually) only take out itself.
> philosophically the same
Diametrically opposed. In one model, the active process voluntarily relinquishes the CPU, and until it does, nothing else will run. In the other, the scheduler pulls the CPU out from under the running thread, to switch to another thread.
You are talking down to me in your technical explanations. I know how it worked.
My point is the cooperative model was an approximation of what you get with preemption. Eventually something yields. A casual user and even many programmers would most certainly not notice a huge difference outside of extraordinary circumstances. In many instances you write code the same way. In many instances a user sees more or less the same thing.
A busy loop without a yield or a hanging program is one of those exceptional circumstances. It didn't happen even a majority of the time.
If the model were radically different, then Win32 would look way more different than Win16 than it did. But you can change the model without throwing out most APIs. If it were anything like the joke "come from" proposals, that wouldn't be the case.
goto is one of those things that you're actively discouraged from using or ever thinking about without ever knowing why or having to read "Goto Considered Harmful." goto at least in C is the only way to implement exception handling in a way that properly separates the good path from the bad path without having many sets of nested conditionals after which most of the line becomes whitespace. It is also the only way to exit a deeply nested loop as well. It should be discouraged, especially jumping backwards, but it is necessary in some few cases, at least in C particularly.
I think goto in C with its labels, as a last resort where C's library of structured control flow constructs fail, is a much less bad thing than GOTO in BASIC with its line numbers and much more limited structured control flow.
You can implement sane exception handling in C by the means of few simple preprocessor macros. In fact, this is how exception handling is implemented in ObjectiveC and how it is done in Windows (and this hack is also the reason why Windows have three different ABIs wrt. exception handling)
And in fact, implementing Common Lisp style condition system that can be used from C code in reasonably straightforward way involves only 1kLoC of cpp magic, been there, done that ;)