Thread overview
opIndexOpAssignOpDispatch
Jun 15
monkyyy
Jun 15
Basile B.
Jun 18
Basile B.
June 15
mystruct foo;
foo[1337].isnull=true;

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

it fits the naming scheme!

June 15

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

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

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

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

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.