opendlang / opend

Boost Software License 1.0
76 stars 17 forks source link

Add opUnaryRight #31

Closed IgorDeepakM closed 5 months ago

IgorDeepakM commented 5 months ago

Added the ability to overload the post increment/decrement using opUnaryRight.

This PR was originally inspired by this issue.

https://issues.dlang.org/show_bug.cgi?id=20123

PR: https://github.com/dlang/dmd/pull/12301

The intention was to be able to disable the post inc/dec in order to avoid any problems regarding atomic operation.

One post in the PR was

as in the only thing you are allowed to do with opUnaryRight is to @disable it.

For the moment. Give it some days and people in the forums will demand it to be usable properly.

Currently the post inc/dec is implemented by lowering only without any possbility to override it, https://dlang.org/spec/operatoroverloading.html.

e-- becomes (auto t = e, e.opUnary!"--", t) e++ becomes (auto t = e, e.opUnary!"++", t)

which is restrictive. Why not go with the full functionality in order to be able to customize the post inc/dec. This for example enables C++ like atomics. This change will also help porting from C++ in general.

Ex.

struct Atomic(T)
{
    T val;

    T opUnary(string op)()
    {
        if (op == "++") 
        {
            return val.atomicFetchAdd(1) + 1;
        }
        else if(op == "--")
        {
            return val.atomicFetchSub(1) - 1;
        }

        assert(false);
    }

    T opUnaryRight(string op)()
    {
        if (op == "++") 
        {
            return val.atomicFetchAdd(1);
        }
        else if(op == "--")
        {
            return val.atomicFetchSub(1);
        }

        assert(false);
    }
}

According to: https://en.cppreference.com/w/cpp/atomic/atomic/operator_arith

Another problem without overloading post inc/dec is that the lowering demands that the return type must be of the same type as the operator type.

    struct S { ... }
    S v;

    S r1 = v++; // works
    int r2 = v++; // will never work

This change remain compatible with existing code. The trigger is that as soon the programmer adds opUnaryRight to the type, the compiler will instead try to insert the call instead of lowering.