www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 23960] New: opApply and opApplyReverse should work with named

https://issues.dlang.org/show_bug.cgi?id=23960

          Issue ID: 23960
           Summary: opApply and opApplyReverse should work with named
                    mixin templates in aggregates
           Product: D
           Version: D2
          Hardware: x86
                OS: Linux
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: witold.baryluk+d gmail.com

https://godbolt.org/z/9qcGnWz8G

template M(int value) {
  int opApply(scope int delegate(ref int i) dg) {
    int v = value;
    return dg(v);
  }
}

struct S {
  mixin M!5 m1;
  mixin M!6 m2;
}

void main() {
  import std.stdio : writefln;
  S s;
  foreach (i; s.m1) {
    writefln("%d", i);
  }
}

should compile and print 5.

But it does not compile:

dmd 2.094:

<source>(16): Error: expression has no value
Compiler returned: 1


gdc trunk (14.0.0 20230530):

 <source>:16:3: error: invalid 'foreach' aggregate 's.mixin M!5 m1;
   ' of type 'void'
   16 |   foreach (i; s.m1) {
      |   ^
Compiler returned: 1



I discovered this problem when implementing intrusive circular double-linked
list, which I have two per Node (each node is a member of two intrusive
circular double-linked lists, each with prev and next pointers), where I wanted
to use opApply and opApplyReverse to traverse each list independently on
demand. I am implementation DLX algorithm (Knuth's Algorithm X brute force
depth-first backtracking algorithm for finding solutions to exact cover problem
using dancing links technique).

For opApply, it can be worked around using a delegate:

void main() {
  import std.stdio : writefln;
  S s;
  foreach (i; &s.m1.opApply) {
    writefln("%d", i);
  }
}

but one cannot use `foreach_revserse` on delegates, instead one needs to use
`foreach` with `&s.m1.opApplyReverse` which is less readable and restricts
usage. It also does not work well if there are many opApply and/or
opApplyReverse overloads, possibly templated, as then one cannot form delegate
without explicit instantiation.

Of course if there is only one unnamed mixin, it should be possible to still
use it via class/struct scope:

foreach (i; s),   which will automatically find opApply

and if there are multiple, either ambiguity reported, or aliases uses to
provide an overload set. (This is already implemented in current D version).

--
Jun 04 2023