Comment #0 by default_357-line — 2018-04-13T08:56:30Z
Blocks are a generalization of foreach opApply overloading. They allow
any struct expression to be followed by a statement, which is packaged
into a delegate that returns a control flow type (or, if you want to be
cheap about it, an int like opApply does) and passed to opBlock in
the struct, which decides the control flow of the statement.
Advantages:
* callback-heavy code looks a lot more straightforward
* break/continue/return can be used from within what would otherwise be callbacks
* reduce lambda abuse for control flow (.each is a natural candidate)
* comparatively little effort because it's just an extension of opApply
Example:
import core.controlflow;
struct indefinitely
{
// alternatively: opBlockLoop for 'opBlock that handles break/continue'
static ControlFlow opBlock(ControlFlow delegate() action)
{
while (true)
{
auto flow = action();
// flow.ended: control flow reached end of block
// otherwise, something like a return statement, break, continue or goto
if (!flow.ended) return flow;
}
}
Usage:
indefinitely {
writeln("This is repeated indefinitely.");
}
Other cool example:
If combined with variable declaration expressions, a construct like foreach can in theory be implemented entirely in the library:
ForeachStruct foreach(T)(T iterable, out int indexVariable, out ElementType!T loopVariable) - array.foreach(int index, auto value) { return value; }
Comment #1 by simen.kjaras — 2018-04-13T14:56:49Z
I'd suggest posting this on the forum. You're gonna have to write a DIP for it to actually be added to the language.
This definitely needs more detail about the behavior of 'break', 'continue' and 'return' - constructs that don't make sense in all possible use cases. There should be a way to declare which of these are valid.
I'd also like to see more complete examples. While your 'indefinitely' example is great, it does not show how to deal with arguments - multiple input, multiple output, inference. For instance, what would myFoo look like in a case like this:
myFoo (ref e, out int n, float f; a, b) {
if (f < 1) continue;
n = e * f;
e++;
if (f > 2) break;
if (e == 14) return;
}
(feel free to use a completely different example, this is just to highlight the different complications possible)
Comment #2 by hsteoh — 2018-04-18T14:53:51Z
This definitely needs to be discussed in the forum, and will need a DIP if there's any hope of actually implementing it.
(And great idea BTW; I came up with a similar idea a long time ago but didn't pursue it beyond a cursory forum discussion. Perhaps you'll have better luck this time.)
Comment #3 by robert.schadek — 2024-12-13T18:58:21Z