opApply with/without ref

Steven Schveighoffer schveiguy at yahoo.com
Fri Jan 13 07:10:57 PST 2012

On Thu, 12 Jan 2012 22:49:49 -0500, H. S. Teoh <hsteoh at quickfur.ath.cx>  

> Hi all,
> I'm experimenting with overloading foreach() with opApply, and I found
> that this code doesn't compile:
> 	class C {
> 		void opApply(int delegate(uint n) cb) const {
> 			...
> 		}
> 	}
> 	unittest {
> 		auto c = new C;
> 		foreach (n; c) {
> 			...
> 		}
> 	}
> I get this error:
> Error: function intset.intset.opApply (int delegate(uint n) cb) is not
> callable using argument types (int delegate(ref uint __applyArg0) @safe)
> Eventually I found out that it's because the argument to the delegate
> must be a ref, that is, opApply must be modified to read:
> 	void opApply(int delegate(ref uint n) cb) const {
> 		...
> 	}
> This appears to be the case whether or not I write foreach(n; C) or
> foreach(ref n; C). My question is, is this a compiler bug, or is this
> intentional in the language? If the latter, why?

It's been around for a while.  It was designed that way, I think without  
knowing how bad it would be.  Back then, there was no const, so it  
probably wasn't imagined how it would affect things.

What the compiler does when you do foreach without a ref is transform your  
non-ref foreach body into a ref one (it essentially just makes a temporary  
copy of the ref coming in).

This means if you don't actually want the data to change via foreach, you  
have to make an lvalue copy in your opApply, pass it to the ref delegate,  
which will then be copied into a local variable.  It's a ridiculous  
workaround of D.

I've filed a bug on it a long time ago (2008), I think it has been fixed  
in git head last December, I haven't tested it.


If you feel adventurous, you could try compiling a git clone copy of dmd  
to see if it works.


More information about the Digitalmars-d-learn mailing list