Thread overview
How to alias
Jan 14, 2022
kyle
Jan 14, 2022
Adam D Ruppe
Jan 14, 2022
kyle
Jan 18, 2022
Adam D Ruppe
Jan 20, 2022
Salih Dincer
January 14, 2022

I'm trying to use alias in an operator overload to reduce typing, but what gets aliased is not what I expect. Tested in DMD v2.098.1-dirty on Windows plus whatever versions of DMD, GDC, and LDC I have installed on Linux. Thanks.

struct Broke
{
    double num;

    import std.traits : isNumeric;
    Broke opBinary(string op, T)(T rhs) if (is(T : Broke) || isNumeric!T)
    {
        static if ( is(T : Broke))
        {
            alias b = rhs.num;
            assert(&b != &this.num); //this fails
        }
        else
        {
            alias b = rhs;
        }

        static if (op == "+")
        {
            return Broke(num + b);
        }
    }
}

void main()
{
    import std.stdio;

    Broke foo = Broke(10);
    Broke bar = Broke(20);

    writeln(foo + 15);  //prints 25 as expected
    writeln(foo + bar); //prints 20
}
January 14, 2022
On Friday, 14 January 2022 at 17:48:41 UTC, kyle wrote:
> I'm trying to use ```alias``` in an operator overload to reduce typing, but what gets aliased is not what I expect.

alias works in term of compile-time names, not values. This means the `this` value, being run time, gets discarded.

alias b = rhs.num;

drops the this, instead doing something more like `alias b = Broke.num;`. It'd work if it was static, or if you re-attach the this later, which is what actually happens in that assert, but not otherwise. This commonly surprises people but the behavior is sometimes useful, i just wish it didn't look the same as something so different.

Easiest thing to do instead is to just use a ref helper function:

            ref b() { return rhs.num; }
            assert(&b() != &this.num); //this works now

(With the -preview=shortenedMethods you can write it `ref b() => rhs.num;` too nut in both cases, you must call the function as b() when you use it)


Or, of course here, the num is just a value so you can simply use an intermediate variable too.

January 14, 2022
On Friday, 14 January 2022 at 17:56:48 UTC, Adam D Ruppe wrote:
> On Friday, 14 January 2022 at 17:48:41 UTC, kyle wrote:
>> [...]
>
> alias works in term of compile-time names, not values. This means the `this` value, being run time, gets discarded.
>
> [...]

Thanks Adam. We need a repository of articles about stuff that doesn't do what people expect.
January 18, 2022
On Friday, 14 January 2022 at 18:04:35 UTC, kyle wrote:
> Thanks Adam. We need a repository of articles about stuff that doesn't do what people expect.

I put this as a tip of the week in my late post:
http://dpldocs.info/this-week-in-d/Blog.Posted_2022_01_10.html#tip-of-the-week

My blog sometimes gets these if you do a ctrl+f search on the index sometimes something will come up.
January 20, 2022

On Friday, 14 January 2022 at 17:48:41 UTC, kyle wrote:

>
void main()
{
    import std.stdio;

    Broke foo = Broke(10);
    Broke bar = Broke(20);

    writeln(foo + 15);  //prints 25 as expected
    writeln(foo + bar); //prints 20
}

I guess what you want to do is something like this:

struct Broke
{
    double num;

    Broke opBinary(string op)(Broke rhs)
    if(op == "+")
    {
      return Broke(this.num + rhs.num);/*
      this.num += rhs.num;
      return this;//*option 2*/
    }

    Broke opBinary(string op)(double rhs)
    if(op == "+")
    {
      return Broke(this.num + rhs);/*
      this.num += rhs;
      return this;//*option 2*/
    }
}

void main()
{
    import std.stdio;

    Broke foo = Broke(5);
    Broke bar = Broke(15);
    bar = foo + bar;    // #1 bar == Broke(20)

    writeln(foo + 15);  // #2 print ok => 20
    writeln(foo + bar); // #3 print ok => 25
}

So you don't need to use alias. If you want it the other way (option 2), turn off option 1 then option 2 will open automatically. Thus, same Broke() gets values: 20, 35 and 55.

regards,

  • Salih