Thread overview
How to alias
Jan 14
kyle
Jan 14
kyle
January 14

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

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