Thread overview
opIndexOpAssignOpDispatch
Jun 15, 2024
monkyyy
Jun 15, 2024
Basile B.
Jun 17, 2024
Quirin Schroll
Jun 18, 2024
Basile B.
Jun 20, 2024
Quirin Schroll
Jun 20, 2024
Quirin Schroll
June 15, 2024
mystruct foo;
foo[1337].isnull=true;

=>
foo.opIndexOpAssignOpDispatch!"isnull"(1337,true)

it fits the naming scheme!

June 15, 2024

On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:

>
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.

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 !

June 17, 2024

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:

>
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.

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 !

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;
}
June 18, 2024

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:

>
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.

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 !

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

June 20, 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:

>
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.

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 !

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:

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
}
June 20, 2024

On Saturday, 15 June 2024 at 04:58:58 UTC, monkyyy wrote:

>
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 or XL.