Custom Blocks

Chris Williams aahz at seanet.com
Tue Aug 10 10:12:41 PDT 2010


== Quote from Andrei Alexandrescu (SeeWebsiteForEmail at erdani.org)'s
article
> FWIW we've been talking a long time ago about a simple lowering - if
the
> last argument to a function is a delegate, allow moving the
delegate's
> body outside of the function:
> fun(a, b, c) { body }
>   |
>   V
> fun((a, b, c) { body });
> As far as Walter and I could tell, there are no syntactical issues
> created by such a lowering.

Thinking about this a bit more, essentially we are doing the same
thing as foreach<->opApply, where we have a function receiving a
delegate that will probably be optimized into a local block. There are
some key differences, though.

Firstly, I can do this with your method:

void doOnce(int delegate() dg) {
	static bool done = false;
	if (!done) {
		done = true;
		writefln("%s", dg());
	}
}

int main() {
	for (uint i = 0; i < 5; i++) {
		doOnce() {
			return 42;
		}
		...do stuff
	}

	return 0;
}

Having a return value sitting in the middle of what looks like a local
block is a bit ugly. It seems like main() will end at "return 42". For
creating something that operates like a code block, we would never
want a return.

That brings us to the second problem. Our last parameter for a custom
block is always "void delegate()" and our return is always void.
There's nothing to be gained by forcing the coder to write both.

I'll grant that the delegate passing solution is overall prettier than
the macro version I suggested in the original post. The ability to
create a doOnce block that can be re-used in multiple places is lost
by using delegates since the static variable will only exist in one
place, but I can't say that the ability is a major one. The syntax I
presented can be easily updated to match your version by the creation
of an assumed void delegate() called $.

block readLock(IRWLock o) {
   o.readLock();
   scope (exit) o.readUnlock();
   $();
}


More information about the Digitalmars-d mailing list