www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Why is opIndexAssign replaced by opSlice here?

reply Elmar <chrehme gmx.de> writes:
Hello Dear community.

I'd like to overload `opIndexAssign` for a struct which wraps 
around a generic array (so that it can't support `opIndex` due to 
unknown return type).

Broken down as much as possible this is the code:

```
import std.stdio : writeln;
import std.range : ElementType;

struct S {
	void opIndexAssign(X, RANGE)(X x, RANGE range)
		if (is(ElementType!RANGE : size_t))
	{
		writeln(__FUNCTION__);
	}

	auto opSlice(size_t start, size_t end) {
		import std.range : iota;
		return iota(start, end);
	}
}

void main()
{
	auto arr = new int[7];

	S s;
	s.opIndexAssign(arr, s.opSlice(1,4));  // works
	s[0..3] = arr[1..4];  // does not work, compiles to 
`s.opSlice(0,3) = arr[1..4]`
}
```

I'm clueless about why it wouldn't compile the last statement to 
`s.opIndexAssign(arr[1..4], s.opSlice(0,3))`.

Help appreciated :-)
Oct 17 2021
next sibling parent Elmar <chrehme gmx.de> writes:
Btw, I should have written:

`s.opIndexAssign(arr[1..4], s.opSlice(0,3));`

But it compiles the same way.
Oct 17 2021
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 17 October 2021 at 22:52:27 UTC, Elmar wrote:
 Hello Dear community.

 I'd like to overload `opIndexAssign` for a struct which wraps 
 around a generic array (so that it can't support `opIndex` due 
 to unknown return type).

 Broken down as much as possible this is the code:

 ```
 import std.stdio : writeln;
 import std.range : ElementType;

 struct S {
 	void opIndexAssign(X, RANGE)(X x, RANGE range)
 		if (is(ElementType!RANGE : size_t))
 	{
 		writeln(__FUNCTION__);
 	}

 	auto opSlice(size_t start, size_t end) {
 		import std.range : iota;
 		return iota(start, end);
 	}
 }

 void main()
 {
 	auto arr = new int[7];

 	S s;
 	s.opIndexAssign(arr, s.opSlice(1,4));  // works
 	s[0..3] = arr[1..4];  // does not work, compiles to 
 `s.opSlice(0,3) = arr[1..4]`
 }
 ```

 I'm clueless about why it wouldn't compile the last statement 
 to `s.opIndexAssign(arr[1..4], s.opSlice(0,3))`.

 Help appreciated :-)
What happens here is, the compiler first tries the D2-style rewrite: ```d s.opIndexAssign(arr[1..4], s.opSlice!0(0, 3)) ``` However, that rewrite fails to compile, because your `opSlice` does not take a template argument specifying the dimension along which to slice, as specified in the language spec's section on ["Slice Operator Overloading".][1] Since the above rewrite fails to compile, it falls back to rewriting the expression using D1-style operator overloads:
 For backward compatibility, `a[]` and `a[i..j]` can also be 
 overloaded by implementing `opSlice()` with no arguments and 
 `opSlice(i, j)` with two arguments, respectively. This only 
 applies for one-dimensional slicing, and dates from when D did 
 not have full support for multidimensional arrays. This usage 
 of opSlice is discouraged.
...which results in the following rewritten statement: ```d s.opSlice(0, 3) = arr[1..4]; ``` My guess is that you got into this situation by trying to follow the example in the spec's section on ["Slice Assignment Operator Overloading"][2]. Unfortunately, that example is incorrect. Here is a fixed version of your example on run.dlang.io: https://run.dlang.io/is/dtfT5y [1]: https://dlang.org/spec/operatoroverloading.html#slice [2]: https://dlang.org/spec/operatoroverloading.html#slice_assignment_operator
Oct 17 2021
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Monday, 18 October 2021 at 03:42:35 UTC, Paul Backus wrote:
 My guess is that you got into this situation by trying to 
 follow the example in the spec's section on ["Slice Assignment 
 Operator Overloading"][2]. Unfortunately, that example is 
 incorrect.

 [2]: 
 https://dlang.org/spec/operatoroverloading.html#slice_assignment_operator
https://issues.dlang.org/show_bug.cgi?id=22417 https://github.com/dlang/dlang.org/pull/3113
Oct 17 2021
parent Imperatorn <johan_forsberg_86 hotmail.com> writes:
On Monday, 18 October 2021 at 04:11:18 UTC, Paul Backus wrote:
 On Monday, 18 October 2021 at 03:42:35 UTC, Paul Backus wrote:
 My guess is that you got into this situation by trying to 
 follow the example in the spec's section on ["Slice Assignment 
 Operator Overloading"][2]. Unfortunately, that example is 
 incorrect.

 [2]: 
 https://dlang.org/spec/operatoroverloading.html#slice_assignment_operator
https://issues.dlang.org/show_bug.cgi?id=22417 https://github.com/dlang/dlang.org/pull/3113
Gold star for fixing broken examples 🌟
Oct 17 2021
prev sibling parent Elmar <chrehme gmx.de> writes:
On Monday, 18 October 2021 at 03:42:35 UTC, Paul Backus wrote:
 What happens here is, the compiler first tries the D2-style 
 rewrite:

 ```d
 s.opIndexAssign(arr[1..4], s.opSlice!0(0, 3))
 ```

 However, that rewrite fails to compile, because your `opSlice` 
 does not take a template argument specifying the dimension 
 along which to slice, as specified in the language spec's 
 section on ["Slice Operator Overloading".][1]

 Since the above rewrite fails to compile, it falls back to 
 rewriting the expression using D1-style operator overloads:

 For backward compatibility, `a[]` and `a[i..j]` can also be 
 overloaded by implementing `opSlice()` with no arguments and 
 `opSlice(i, j)` with two arguments, respectively. This only 
 applies for one-dimensional slicing, and dates from when D did 
 not have full support for multidimensional arrays. This usage 
 of opSlice is discouraged.
...which results in the following rewritten statement: ```d s.opSlice(0, 3) = arr[1..4]; ``` My guess is that you got into this situation by trying to follow the example in the spec's section on ["Slice Assignment Operator Overloading"][2]. Unfortunately, that example is incorrect. Here is a fixed version of your example on run.dlang.io: https://run.dlang.io/is/dtfT5y [1]: https://dlang.org/spec/operatoroverloading.html#slice [2]: https://dlang.org/spec/operatoroverloading.html#slice_assignment_operator
Woow! You fixed the problem, it now works for me. I wish the compiler would have been able to make me understand the problem. It was no help because it only tells the final erroneous consequence, that the return value of `opSlice` cannot be assigned ("is no lvalue", beginner-unfriendly language). It doesn't even mention `opSlice` or the fallback (reason) with no warning.
Oct 18 2021