www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - input range with non copyable element

reply vit <vit vit.vit> writes:
Hello, is there reason why elements of input range must be 
copyable?

For example this example works and copy ctor is never called:

```d
import std.algorithm : map;
import std.range;

struct Foo{
	int i;

     this(scope ref typeof(this) rhs)pure nothrow  safe  nogc{
     	//this.i = rhs.i;
         assert(0, "no copy");
     }
	 disable this(scope const ref typeof(this) rhs)pure nothrow 
 safe  nogc;
}


void main(){
     Foo[] foos = [Foo(1), Foo(2), Foo(3)];

     //this work (copy ctor is never called):
     {
         auto tmp = foos
             .map!((ref foo) => foo.i)
             .array;
     }
}
```

This doesn't work:


```d

void main(){
     const(Foo)[] foos = [Foo(1), Foo(2), Foo(3)];

     //error:
     {
         auto tmp = foos
             .map!((ref foo) => foo.i)
             .array;
     }
}
```

Source of my problem is in `isInputRange`:
```d
import std.range;
import std.traits : ReturnType;

alias R = const(Foo)[];
//enum bool isInputRange(R) =
static assert(is(typeof(R.init) == R));								///OK
static assert(is(ReturnType!((R r) => r.empty) == bool));			///OK
static assert(is(typeof((return ref R r) => 
r.front)));				///ERROR, copy result of front
static assert(!is(ReturnType!((R r) => r.front) == void));			///OK
static assert(is(typeof((R r) => r.popFront)));						///OK
```

Is it possible to make lambda return `auto ref`?
Aug 08 2021
parent reply Mathias LANG <geod24 gmail.com> writes:
On Sunday, 8 August 2021 at 18:36:02 UTC, vit wrote:
 Hello, is there reason why elements of input range must be 
 copyable?
By design, not that I can think of. But it is assumed all over the place, unfortunately. You can make your `front` method return by `ref`, but you're still going to get bitten as soon as you do any `std.algorithm`-based operation, as storage classes are not inferred (https://issues.dlang.org/show_bug.cgi?id=9423) and things get passed by value to your delegates by default. The problem can also show up when you `foreach` over a range (https://issues.dlang.org/show_bug.cgi?id=15413). And finally, `std.algorithm` need to support it. So currently you'll have to jump through a lot of hops to get it to work. It'll be much easier to use your own `map` & co to get the job done for the time being. Hopefully at some point in the near future that won't be needed anymore.
Aug 08 2021
parent vit <vit vit.vit> writes:
On Monday, 9 August 2021 at 02:47:40 UTC, Mathias LANG wrote:
 On Sunday, 8 August 2021 at 18:36:02 UTC, vit wrote:
 Hello, is there reason why elements of input range must be 
 copyable?
By design, not that I can think of. But it is assumed all over the place, unfortunately. You can make your `front` method return by `ref`, but you're still going to get bitten as soon as you do any `std.algorithm`-based operation, as storage classes are not inferred (https://issues.dlang.org/show_bug.cgi?id=9423) and things get passed by value to your delegates by default. The problem can also show up when you `foreach` over a range (https://issues.dlang.org/show_bug.cgi?id=15413). And finally, `std.algorithm` need to support it. So currently you'll have to jump through a lot of hops to get it to work. It'll be much easier to use your own `map` & co to get the job done for the time being. Hopefully at some point in the near future that won't be needed anymore.
Look like I am not the first who has this problem: https://issues.dlang.org/show_bug.cgi?id=14478 I copy part of `std.algorithm` I use and change `isInputRange` to: ```d enum bool isInputRange(R) = true && is(typeof(R.init) == R) ///no change && is(ReturnType!((R r) => r.empty) == bool) ///no change && is(typeof((return ref R r) => (auto ref x){}(r.front))) ///Before: , is(typeof((return ref R r) => r.front)) && !is(ReturnType!((R r) => r.front) == void) ///no change && is(typeof((R r) => r.popFront)); ///no change
Aug 09 2021