On Monday, 7 June 2021 at 15:55:36 UTC, H. S. Teoh wrote:

Thanks for your reply. It was very illustrating.

It's very simple. Whenever some non-array object appears on the right side of a foreach() statement, the compiler looks for a method on the object called .opApply. If it exists, the loop body is passed to that method as a delegate. IOW:

```d
        // This:
        foreach (item; myCollection) {
                /* loop body here */
        }

        // Gets translated to this:
        myCollection.opApply((item) { /* loop body here */ });
```

Given that, your .opApply method doesn't really do what you want. It should instead be written like this:

        // N.B.: dg is NOT the type of the collection, but the
        // individual item you want to iterate over.

```d
        int opApply(int delegate(classComputer) dg)
        {
                // Loop over the computers in the current node first
                foreach (computer; computers) {
                        // Pass single item to loop body.
                        auto ret = dg(computer);

                        // N.B.: do NOT assume a non-zero return value
                        // will always be 1; it may not be if your loop
                        // body contains `break` or `continue`.
                        if (ret) return ret;
                }

                // Now recurse child nodes
                if (lhs) {
                        auto ret = lhs.opApply(dg);
                        if (ret) return ret; // again, don't assume it will be 1
                }
                if (rhs) {
                        auto ret = rhs.opApply(dg);
                        if (ret) return ret; // again, don't assume it will be 1
                }
                return 0;
        }
```

For the sake of clarity (to me) and, given I never liked code with multiple returns, I rewrote your code (providing I am not introducing flaws) as following:

```d
class classComputers {

   classComputers lhs;
   classComputers rhs;

int opApply(int delegate(classComputer) dg) { /// boilerplate code to handle the class's default collection

      int lintResult = 0;

foreach (lobjComputer; computers) { /// looping over the computers starting in current node

lintResult = dg(lobjComputer); /// passing single object to the loop body

                        if (lintResult != 0) { break; }

                }

if (lintResult != 0 && lhs) { lintResult = lhs.opApply(dg); } /// recursing child nodes if (lintResult != 0 && rhs) { lintResult = rhs.opApply(dg); } /// recursing child nodes

      return lintResult;

   }

public classComputer[] computers; alias computers this; /// ie: default property

}
```

It seems it works perfectly well.

Also, your:

```d
alias computers this;
```

was very clever, indeed :)

Reply via email to