The magic behind foreach (was: Re: Descent 0.5.3 released)

Ary Borenszweig ary at esperanto.org.ar
Thu Jan 22 15:52:25 PST 2009


Bill Baxter wrote:
> On Fri, Jan 23, 2009 at 8:10 AM, Christopher Wright <dhasenan at gmail.com> wrote:
>> Ary Borenszweig wrote:
>>> If the compiler can transform a "foreach" into an opApply call, passing
>>> the foreach body and converting breaks to "return 1" statements... can't
>>> opApply be specified as:
>>>
>>> int opApply(void delegate(ref uint) dg) { // note: delegate returns void
>>> }
>>>
>>> and the compiler transforms the opApply signature to the one that's used
>>> now, plus converting each dg call to a call and a check of return value  !=
>>> 0 and return 1 in that case?
>> This only fails if you wish to take a particular action when the calling
>> code breaks out of iteration. This is not such a large use case that I think
>> it worth preserving.

Why do you mean by "fails"? The compiler transforms the foreach's body, 
it can transform the opApply's body.

> 
> It's not?
> 
> foreach(i;  things) {
>       if (i==a) continue;
>       if (i==b) break;
>       if (i==d) return;
>       if (i==c) goto somewhere;
> }
> 
> Those are all fairly common things to do from inside the 'dg' call.
> The int is how the compiler distinguishes which case got you out of
> the dg.
> 
> --bb

Aaaah... Now I see what's the return value of opApply for. So I tried 
your code:

(just the relevant piece)
---
int main(char[][] args) {
	int a = 1, b = 2, c = 3, d = 4;
	
     Foo foo = new Foo();
     foreach(i; foo) {
     	if (i==a) continue;
         if (i==b) break;
         if (i==d) return;
         if (i==c) goto somewhere;
     }

     somewhere:

     return 0;
}
---

and DMD spits out this:

---
int main(char[][] args) {
	int a = 1, b = 2, c = 3, d = 4;
	
	Foo foo = new Foo;
	switch(foo.opApply(delegate (uint __applyArg0) {
			{
				uint i = __applyArg0;
				if(i == cast(uint) a)
					return 0;
				if(i == cast(uint) b)
					return 1;
				if(i == cast(uint) d)
					return 2;
				if(i == cast(uint) c)
					return 3;
			}
			return 0;
		} )) {
		default:
			break;
		case 2:
			return;
		case 3:
			goto somewhere;
	}
	
	somewhere:
	
	return 0;
}
---

Intersting. The compiler (Walter?) is being smart here. :-)



More information about the Digitalmars-d mailing list