Does D have too many features?

deadalnix deadalnix at gmail.com
Mon Apr 30 05:37:40 PDT 2012


Le 30/04/2012 06:20, H. S. Teoh a écrit :
> 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.
>

This make sense. This seems to me like the way to go.


More information about the Digitalmars-d mailing list