Re: Why is opIndexAssign replaced by opSlice here?

2021-10-18 Thread Elmar via Digitalmars-d-learn

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.


Re: Why is opIndexAssign replaced by opSlice here?

2021-10-17 Thread Imperatorn via Digitalmars-d-learn

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 


Re: Why is opIndexAssign replaced by opSlice here?

2021-10-17 Thread Paul Backus via Digitalmars-d-learn

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


Re: Why is opIndexAssign replaced by opSlice here?

2021-10-17 Thread Paul Backus via Digitalmars-d-learn

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


Re: Why is opIndexAssign replaced by opSlice here?

2021-10-17 Thread Elmar via Digitalmars-d-learn

Btw, I should have written:

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

But it compiles the same way.


Why is opIndexAssign replaced by opSlice here?

2021-10-17 Thread Elmar via Digitalmars-d-learn

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 :-)