opIndexOpAssignOpDispatch
Quirin Schroll
qs.il.paperinik at gmail.com
Thu Jun 20 10:50:19 UTC 2024
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
}
```
More information about the dip.ideas
mailing list