www.digitalmars.com         C & C++   DMDScript  

digitalmars.dip.ideas - opIndexOpAssignOpDispatch

reply monkyyy <crazymonkyyy gmail.com> writes:
```d
mystruct foo;
foo[1337].isnull=true;
```
=>
`foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

it fits the naming scheme!
Jun 14
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:
 ```d
 mystruct foo;
 foo[1337].isnull=true;
 ```
 =>
 `foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

 it fits the naming scheme!
You can implement an opIndex overload that returns a struct that itself supports opDispatch. ```d struct Foo { struct opIndexResult { Foo* that; auto opDispatch(string member, T)(T t) { } } auto opIndex(T)(T t) { return opIndexResult(&this); } } void main() { Foo foo; foo[1337].isnull = true; } ``` dont underestimate what's already possible !
Jun 15
parent reply Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Saturday, 15 June 2024 at 08:33:07 UTC, Basile B. wrote:
 On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:
 ```d
 mystruct foo;
 foo[1337].isnull=true;
 ```
 =>
 `foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

 it fits the naming scheme!
You can implement an opIndex overload that returns a struct that itself supports opDispatch. ```d struct Foo { struct opIndexResult { Foo* that; auto opDispatch(string member, T)(T t) { } } auto opIndex(T)(T t) { return opIndexResult(&this); } } void main() { Foo foo; foo[1337].isnull = true; } ``` dont underestimate what's already possible !
```d struct Foo { struct opIndexResult(bool isRef, Arg) { Foo* that; static if (isRef) { Arg* _arg; ref Arg arg() => *_arg; } else { Arg _arg; ref Arg arg() return => _arg; } auto ref opDispatch(string member, Rhs)(Rhs rhs) { import std.stdio; writeln("Called <something>[", arg, "].", member, " = ", rhs); } } auto ref opIndex(T)(auto ref T t) { alias Result = opIndexResult!(__traits(isRef, t), T); static if (__traits(isRef, t)) { return Result(&this, &t); } else { import core.lifetime : move; return Result(&this, move(t)); } } } void main() safe { Foo foo; foo[1337].isnull = true; } ```
Jun 17
parent reply Basile B. <b2.temp gmx.com> writes:
On Monday, 17 June 2024 at 13:40:13 UTC, Quirin Schroll wrote:
 On Saturday, 15 June 2024 at 08:33:07 UTC, Basile B. wrote:
 On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:
 ```d
 mystruct foo;
 foo[1337].isnull=true;
 ```
 =>
 `foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

 it fits the naming scheme!
You can implement an opIndex overload that returns a struct that itself supports opDispatch. ```d struct Foo { struct opIndexResult { Foo* that; auto opDispatch(string member, T)(T t) { } } auto opIndex(T)(T t) { return opIndexResult(&this); } } void main() { Foo foo; foo[1337].isnull = true; } ``` dont underestimate what's already possible !
```d struct Foo { struct opIndexResult(bool isRef, Arg) { Foo* that; static if (isRef) { Arg* _arg; ref Arg arg() => *_arg; } else { Arg _arg; ref Arg arg() return => _arg; } auto ref opDispatch(string member, Rhs)(Rhs rhs) { import std.stdio; writeln("Called <something>[", arg, "].", member, " = ", rhs); } } auto ref opIndex(T)(auto ref T t) { alias Result = opIndexResult!(__traits(isRef, t), T); static if (__traits(isRef, t)) { return Result(&this, &t); } else { import core.lifetime : move; return Result(&this, move(t)); } } } void main() safe { Foo foo; foo[1337].isnull = true; } ```
Nice. While the pattern was clear enough to be developped I'm still slightly concerned about escaping `this`. Probably the result should be set non-copiable with ` disable this(this)`.
Jun 18
parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Tuesday, 18 June 2024 at 09:37:46 UTC, Basile B. wrote:
 On Monday, 17 June 2024 at 13:40:13 UTC, Quirin Schroll wrote:
 On Saturday, 15 June 2024 at 08:33:07 UTC, Basile B. wrote:
 On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:
 ```d
 mystruct foo;
 foo[1337].isnull=true;
 ```
 =>
 `foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

 it fits the naming scheme!
You can implement an opIndex overload that returns a struct that itself supports opDispatch. ```d struct Foo { struct opIndexResult { Foo* that; auto opDispatch(string member, T)(T t) { } } auto opIndex(T)(T t) { return opIndexResult(&this); } } void main() { Foo foo; foo[1337].isnull = true; } ``` dont underestimate what's already possible !
```d struct Foo { struct opIndexResult(bool isRef, Arg) { Foo* that; static if (isRef) { Arg* _arg; ref Arg arg() => *_arg; } else { Arg _arg; ref Arg arg() return => _arg; } auto ref opDispatch(string member, Rhs)(Rhs rhs) { import std.stdio; writeln("Called <something>[", arg, "].", member, " = ", rhs); } } auto ref opIndex(T)(auto ref T t) { alias Result = opIndexResult!(__traits(isRef, t), T); static if (__traits(isRef, t)) { return Result(&this, &t); } else { import core.lifetime : move; return Result(&this, move(t)); } } } void main() safe { Foo foo; foo[1337].isnull = true; } ```
Nice. While the pattern was clear enough to be developped I'm still slightly concerned about escaping `this`. Probably the result should be set non-copiable with ` disable this(this)`.
Copies are largely irrelevant. With `-dip1000`, the escaping `Foo` is diagnosed. Improved code: ```d struct Foo { int x; private static struct OpIndexResult(bool[] isRef, Is...) if (isRef.length == Is.length) { import std.meta; Foo* that; static foreach (i; 0 .. Is.length) static if (isRef[i]) { mixin("Is[i]* _index_", i,";"); mixin(" property ref Is[i] index_", i,"() => *_index_",i,";"); } else { mixin("Is[i] _index_", i,";"); mixin(" property ref Is[i] index_", i,"() => _index_",i,";"); } template indices() { alias indices = AliasSeq!(); static foreach (i; 0 .. Is.length) indices = AliasSeq!(indices, mixin("index_", i)); } auto ref opDispatch(string member, Rhs...)(auto ref Rhs rhs) { import std.stdio; import std.typecons : tuple; writefln("Called Foo(%s)[%(%s%|, %)](%(%s%|, %))", that.x, tuple(indices!()), tuple(rhs)); } } auto opIndex(Is...)(auto ref Is indices) return { import core.lifetime : move; enum bool[] isRef = { bool[] result = new bool[](Is.length); static foreach (i; 0 .. Is.length) result[i] = __traits(isRef, indices[i]); return result; }(); alias Result = OpIndexResult!(isRef, Is); return mixin({ string result = "Result(&this"; static foreach (i, alias index; indices) { static if (__traits(isRef, index)) result ~= mixin(`", &indices[`, i, `]"`); else result ~= mixin(`", move(indices[`, i, `])"`); } return result ~ ")"; }()); } } typeof(Foo()[0,0]) global; void main() safe { Foo foo = Foo(1); auto r = foo[1337, 42]; r.isnull(true, false); // Weird, but okay global = foo[1337, 42]; // Error because `foo` escapes } ```
Jun 20
prev sibling parent Quirin Schroll <qs.il.paperinik gmail.com> writes:
On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:
 ```d
 mystruct foo;
 foo[1337].isnull=true;
 ```
 =>
 `foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)`

 it fits the naming scheme!
At this point, D would be getting close to a term language like [Maude](https://en.wikipedia.org/wiki/Maude_system) or [XL](https://xlr.sourceforge.io/#extending-the-syntax).
Jun 20