opApply with/without ref

H. S. Teoh hsteoh at quickfur.ath.cx
Thu Jan 12 19:49:49 PST 2012

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?

More to the point, I'm implementing a class which stores a set of
unsigned numbers in a compact form; I wrote an opApply() method to make
it easy to iterate over. However, the compact representation doesn't
allow arbitrary mutation to set elements. That is, the following is not

	foreach (ref n; c) {

The problem is that this code compiles just fine, because there's no way
to say that opApply is only allowed for non-ref indices, but that it
doesn't do what it appears to say. The collection c is unchanged because
opApply() calls the delegate with a local variable: the number itself is
not actually stored in the data structure, so opApply() computes it
on-the-fly and hands it to the delegate. So modifying n in the foreach
body doesn't actually update the structure, even though it appears to.

How can I specify that only non-ref foreach loops are allowed for this
class? I thought that declaring opApply() the way I did at first (i.e.,
without the ref argument) is the correct way, but obviously the compiler
doesn't like it. (FWIW, I'm using GDC, I don't know if dmd has the same


Lottery: tax on the stupid. -- Slashdotter

More information about the Digitalmars-d-learn mailing list