No need opUnary

Ali Çehreli acehreli at yahoo.com
Mon Dec 19 20:02:53 UTC 2022


On 12/18/22 08:21, Salih Dincer wrote:
 > Don't you think it's interesting that it doesn't need unary operator
 > overloading?

Yes, it is interesting. I put comments to explain it to myself:

import std.stdio;

struct S
{
     int value;

     /* The folowing declaration allows objects of this type to be
        implicitly convertible to 'int' (the return type of
        'opCall').

        In other words, since opCall returns 'int', now we know S
        objects can implicitly be used in place of an int. The
        value will be determined by calling opCall.

        For those of us who may not know opCall, it allows an
        object to be used as a function. For example, when you
        have an 'obj', you can do 'obj()'. (And as seen below, it
        returns 'int' for this struct.)

        (Note: It confused me for a bit because there are two
        opCall definitions below and they both return
        'int'. However, there is no ambiguity because the compiler
        picks the one that takes no parameter for the following
        alias this.)  */
        alias opCall this;

     this(int i) {
         value = i;
     }

     /* I didn't know one could do the following. You are giving a
        new name (opAssign) to opCall. I wonder whether the
        compiler considers opCall for the assignment operation or
        whether it looks for a proper opAssign definition. (Too
        lazy to check...)  */
     alias opAssign = opCall;

     /* This is the function call operator that takes an 'int',
       supporting usages like obj(42). */
     @property opCall(int x) {
         return value = x;
     }

     /* This is the function call opCall that takes nothing,
        supporting usages like obj(). */
     @property opCall() inout {
         return value;
     }

     /* This is the operator overload for usages like 'obj += 42'. */
     @property opOpAssign(string op)(int x) {
         write(":"); // came here before
         mixin("return value"~op~"=x;");
     }
     // no need: opUnary(string op)();
}

void main()
{
     /* Ok, this is regular object construction. */
     S a = S(10),

     /* Using a comma above is something I would never do but 'b' is
       another object being constructed regularly. */
       b = S(-1);

     /* Since S does not define the '+' operation, I think the
        compiler looks and finds an implicit conversion, which
        happens to be to 'int'. I think the following expression
        is addition of two ints: 10 + (-1)' */
     writeln(a + b); // 9

     /* Although S does not support the ++ operator, the D
        compiler finds the += operation and replaces ++ with
        a+=1. And then a is implicitly converted to 'int', gets the
        value 11. Again, the expression is an int addition of 11 +
        (-1). */
     writeln(++a + b); // :10

     /* This uses opOpAssign. */
     a += 10; // :

     /* This result makes sense. */
     assert(a == 21);

     writeln("\n--");

     writeln(-b); // 1
}

Ali



More information about the Digitalmars-d-learn mailing list