Does D have too many features?

H. S. Teoh hsteoh at quickfur.ath.cx
Sun Apr 29 21:20:58 PDT 2012


On Mon, Apr 30, 2012 at 01:57:58AM +0200, Alex Rønne Petersen wrote:
> On 30-04-2012 01:54, Era Scarecrow wrote:
> >On Sunday, 29 April 2012 at 15:07:26 UTC, David Nadlinger wrote:
> >>On Sunday, 29 April 2012 at 14:40:38 UTC, Jacob Carlborg wrote:
[...]
> >>We'd still need a solution for continue and break, though.
> >
> >A thought coming to mind regarding this, is a special exception. If
> >the compiler recognizes it's part of a foreach (or other loop) then
> >continue gets converted to return, and and break throws an exception
> >(caught by the foreach of course)
> >
> >But that involves more compiler magic.
> >
> 
> And forced EH which is unacceptable in e.g. a kernel.
[...]

Here's a wild idea: introduce the concept of the multi-return function
(or, in this case, delegate). Unlike normal functions which returns to a
single point when they end, usually by pushing the return address onto
the runtime stack, a multi-return function is called by pushing
_multiple_ return addresses onto the runtime stack. The function body
decides which return address to use (it can only use one of them).

Implementing break/continue then can be done like this: the loop body
delegate will be a multi-return delegate, i.e., a delegate whose caller
will provide multiple return addresses: one for each possible
break/continue point.  For example:

	outerLoop: foreach (a; containerA) {
		innerLoop: foreach (b; containerB) {
			if (condition1())
				continue outerLoop;

			if (condition2())
				break /* innerLoop */;

			if (condition3())
				break outerLoop;
		}
		if (condition4())
			break /* outerLoop */;
	}

When containerA.opApply is called, it calls the outer loop body with two
return addresses: the first is the usual return address from a function
call, the second is the cleanup code at the end of opApply that performs
any necessary cleanups and then returns. I.e., it simulates break. So
when condition4 triggers, the outerLoop delegate returns to the second
address.

Now the outerLoop delegate itself calls containerB.opApply with a list
of outer loop return addresses, i.e., (1) return to containerA.opApply's
caller, that is, break outerLoop, (2) return to outerLoop delegate's
cleanup code, i.e. continue OuterLoop. Then containerB.opApply prepends
two more return addresses to this list, the usual return address to
containerB.opApply, and its corresponding break return (prepend because
the last return addressed pushed must correspond with the immediate
containing scope of the called delegate, but if the delegate knows about
outer scopes then it can return to those).

Now the innerLoop delegate has four return addresses: return to
containerB.opApply normally (continue innerLoop), return to
containerB.opApply's cleanup code (break innerLoop), return to
containerA.opApply normally (continue outerLoop), and return to
containerA.opApply's cleanup code (break outerLoop). So break/continue
works for all cases.

(Of course, containerB.opApply doesn't actually just prepend return
addresses to what the outerLoop delegate passes in, since when the
innerLoop delegate wants to break outerLoop, it needs to cleanup the
stack frames of the intervening call to containerB.opApply too. So
containerB.opApply needs to insert its own cleanup code into the return
address chain.)

This is, at least, the *conceptual* aspect of things. In the actual
implementation, the compiler may use the current scheme (return an int
to indicate which return is desired) instead of doing what amounts to
reinventing stack unwinding, but the important point is, this should be
transparent to user code. As far as the user is concerned, they just
call the delegate normally, no need to check return codes, etc., with
the understanding that the said delegates have multiple return
addresses. The compiler inserts the necessary scaffolding, checking for
int returns, etc., to actually implement the concept.


T

-- 
WINDOWS = Will Install Needless Data On Whole System -- CompuMan


More information about the Digitalmars-d mailing list