opNext: Simplified ranges

Paul Backus snarwin at gmail.com
Sat Nov 5 18:08:39 UTC 2022


On Saturday, 5 November 2022 at 15:17:42 UTC, Steven 
Schveighoffer wrote:
> This can be solved by a wrapper:
>
> ```d
> struct RefOf(T)
> {
>   private T *_val;
>   ref T _get() { return *_val; }
>   alias _get this;
> }
>
> auto refOf(T)(return ref T val) { return RefOf!T(&val); }
>
> foreach(elem; range.refOf) // now doesn't make a copy.
> ```

You'd think, but if you actually try this, it turns out it 
doesn't work: the compiler is "smart" enough to see through the 
`alias this`, and makes a copy of `range.refOf._get` (the actual 
range object) instead of `range.refOf` (the wrapper).

So, for example, this usage code prints `[1, 2, 3]`, 
demonstrating that the range is *not* consumed by the `foreach` 
loop:

```d
void main()
{
     import std.range, std.stdio;

     auto r = only(1, 2, 3);
     foreach (e; refOf(r)) {}
     writeln(r);
}
```

In the `-vcg-ast` output, you can see the call to `_get` inserted 
by the compiler:

```d
void main()
{
	import std.range;
	import std.stdio;
	OnlyResult!(int, int, int) r = only(1, 2, 3);
	{
		OnlyResult!(int, int, int) __r47 = refOf(r)._get().opSlice();
		for (; !__r47.empty(); __r47.popFront())
		{
			int e = __r47.front();
		}
	}
	writeln(r);
	return 0;
}
```


More information about the Digitalmars-d mailing list