Great post, but the quiz is unfair - it assumes there is only one "true way", but a lot of frameworks give you options
For example, Trio has no global "spawn" method, by design. Judging by the results, authors assumed "with trio.open_nursery() as n: n.start_soon(write_to_log())", and so they got eager execution, dynamic extent, destructive propagation.
But opening a nursery just to write a single log line is absolutely crazy! The real program would use an appropriately scoped shared nursery: either per-request or global. Later option allows indefinite extent and "never" propagation.
Also, that "()" after write_to_log matters! If one follow trio's own examples, you'd write "n.start_soon(write_to_log)" - note no (). This will switch to lazy execution.
I am not familiar with non-python frameworks listed, but I would not be surprised if they allow for similarly wide range of behaviors.
Agreed. I was confused by the Trio example until I reverse engineered what they meant from the outputs. Trio behaves differently (in well-defined, easy to understand ways) depending on where you put nurseries.
I am not talking about "some language", I am talking about specific row in the table, "Python + Trio", which can be ABC or ACB depending on how exactly you implement the code.
For that matter, "Python + Asyncio" is a buggy code as well - if you actually try to run it, you'll get runtime warnings about tasks being garbage collected. Again, ideomatic code would be ACB as well.
Yes. Like I wrote in another comment: authors' expectations and explanations aren't... very convincing. Asking about the order of execution in a concurrent program which certainly can have multiple valid orders by design is unfair.
Also, a lot of discrepancy between results is explained by how long the program waits for spawned but unawaited tasks before exiting. In a realistic program, this situation would be considered a bug (spawning a task w/o awaiting it, and then missing the results because the program exits too soon). I can't imagine a situation where the program's author would intentionally create a situation where non-deterministically, a part of the program might not run...
For example, Trio has no global "spawn" method, by design. Judging by the results, authors assumed "with trio.open_nursery() as n: n.start_soon(write_to_log())", and so they got eager execution, dynamic extent, destructive propagation.
But opening a nursery just to write a single log line is absolutely crazy! The real program would use an appropriately scoped shared nursery: either per-request or global. Later option allows indefinite extent and "never" propagation.
Also, that "()" after write_to_log matters! If one follow trio's own examples, you'd write "n.start_soon(write_to_log)" - note no (). This will switch to lazy execution.
I am not familiar with non-python frameworks listed, but I would not be surprised if they allow for similarly wide range of behaviors.