www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - inout in opAssert in custom range

reply Valentino Giudice <valentino.giudice96 gmail.com> writes:
Consider the following example:

module demo1;

```D
class MyClass
{
     int a;

     this(int a)
     {
         this.a = a;
     }
}

struct MyRange
{
     MyClass[] _items;

     this(MyClass[] items)
     {
         this._items = items;
     }

     int opApply(scope int delegate(inout MyClass item) dg) inout
     {
         for (size_t i = 0; i < this._items.length; i++)
         {
             int result = dg(this._items[i]);
             if (result != 0)
             {
                 return result;
             }
         }
         return 0;
     }

     inout(MyClass) opIndex(size_t i) inout nothrow
     {
         return this._items[i];
     }

     size_t length() const nothrow
     {
         return this._items.length;
     }

     public alias opDollar = length;
}

void main()
{
     MyClass[2] items;
     items[0] = new MyClass(1);
     items[1] = new MyClass(2);

     MyRange r = MyRange(items);

     foreach (MyClass item; r)
     {
         // Operations
     }

     const MyRange r2 = MyRange(items);

     foreach (const MyClass item; r2)
     {
         // Operations
     }
}
```

The idea is that when the range is constant looping should yield 
constant objects and when it's mutable it should yield mutable 
objects.

The code above leads to the following error:

```
Error: cannot uniquely infer `foreach` argument types
     foreach (MyClass item; r)
Error: cannot uniquely infer `foreach` argument types
     foreach (const MyClass item; r2)
```

This problem does not occur if I replace the `inout` declaration 
of `opApply` with the following:

```D
int opApply(scope int delegate(MyClass item) dg)
{
     for (size_t i = 0; i < this._items.length; i++)
     {
         int result = dg(this._items[i]);
         if (result != 0)
         {
             return result;
         }
     }
     return 0;
}

int opApply(scope int delegate(const MyClass item) dg) const
{
     for (size_t i = 0; i < this._items.length; i++)
     {
         int result = dg(this._items[i]);
         if (result != 0)
         {
             return result;
         }
     }
     return 0;
}
```

This is obviously suboptimal and requires duplication of code.

Is there a way to obtain the desired effect without duplicating 
code?

Thank you a lot in advance!
Aug 29
parent monkyyy <crazymonkyyy gmail.com> writes:
On Sunday, 30 August 2026 at 03:28:49 UTC, Valentino Giudice 
wrote:
 
 int opApply(scope int delegate(MyClass item) dg)
 int opApply(scope int delegate(const MyClass item) dg) const
I dont think this does what you think it does; I dont use keywords that can only make less code work but im pretty sure that const does nothing, the way youve written it is confusing yourself, its applied to the int and futhermore opApplies return is a return code for asm gotos ```d import std; struct bar{ const int i; int j; const int front()=>i+j; void popFront(){j++;} bool empty()=>j>10; } unittest{ foreach(const i;bar(2)){ typeof(i).stringof.writeln; } foreach(i;bar(4)){ typeof(i).stringof.writeln; } } ``` the constness of foreach varibles is part of a constructed for loop; d avoid bidirectional type propganging like c++ or haskell (because those languages are slow and buggy when you use it) --- ```d import std; class MyClass{} struct bar{ int opApply(scope int delegate(MyClass item) dg) { for (size_t i = 0; i < 2; i++) { int result = dg(new MyClass()); if (result != 0) { return result; } } return 0; } } unittest{ foreach(const i;bar()){ typeof(i).stringof.writeln; } foreach(i;bar()){ typeof(i).stringof.writeln; } } ``` ``` const(MyClass) const(MyClass) MyClass MyClass ``` you should probably not use opApply if your trying to be safe (opApplys uses are hacks like hotloading and injecting long distance jumps) its just part of foreach, and foreach makes copies anyway unless you say "ref"
Aug 30