July 31, 2018
On 7/30/18 2:30 PM, aliak wrote:
> Is this a bug?
> 
> If not is there a workaround?
> 
> I would like for the alias this to function as a normal A type unless B specifically disables certain features, but it seems weird that disabling one opAssign disables all of them inside the aliases type but not in the aliasing type?
> 
> 
> struct A {
>      void opAssign(int) {}
> }
> struct B {
>      A a;
>      alias a this;
>      @disable void opAssign(float);
> }
> 
> void main() {
>      B b;
>      b = 3;
> }
> 
> Error: function `onlineapp.B.opAssign` is not callable because it is annotated with @disable
> 

OK, so one thing to learn in D, you can't hijack stuff. When you override a function, you have to override ALL the overloads.

What you have done is defined opAssign as ONLY accepting a float, and then disabling any calls to it.

This is obfuscated somewhat by the fact that 3 can be a float as well. So even if you didn't disable the opAssign(float), it would still call that function.

You can get around it by defining a forwarding function for the overloads you want to let through:

@disable void opAssign(float);
auto opAssign(int x) { return a.opAssign(x); }

-Steve
August 01, 2018
On Tuesday, 31 July 2018 at 20:40:25 UTC, Steven Schveighoffer wrote:
> OK, so one thing to learn in D, you can't hijack stuff. When you override a function, you have to override ALL the overloads.

I could have sworn I tested this before I wrote that it's a bug:

struct A {
    void fun(int) {}
}
struct B {
    A a;
    alias a this;
    @disable void fun(float);
}

void main() {
    B b;
    b.fun(3);
}

I was surprised to see it work, as I also thought it'd be a hijacking issue. Turns out, it doesn't actually work. I must have made a typo when I tried it. Ah well.

--
  Simen
August 02, 2018
On Tuesday, 31 July 2018 at 07:01:33 UTC, Simen Kjærås wrote:
> On Monday, 30 July 2018 at 23:41:09 UTC, aliak wrote:
>> https://issues.dlang.org/show_bug.cgi?id=19130
>
> Beautiful. :)
>
>> Would it take much to fix it up to use with templated opAssigns as well?
>
> I spent half an hour doing silly things, then I came up with this:
>
> struct A {
>     void opAssign(int) {}
>     void opAssign(float) {}
>     void opAssign(T)(T t) if (is(T == string)) {}
> }
> struct B {
>     A a;
>     alias a this;
>     @disable void opAssign(float);
>     mixin(wrap!(B, "opAssign"));
>     auto opAssign(T...)(T args)
>     if (__traits(compiles, a.opAssign(args)))
>     {
>         // Look ma, no magic!
>         return a.opAssign(args);
>     }
> }
> unittest {
>     B b;
>     b = "Foo!";
> }
>
> (Remaining code as in my last post)
>
> Yeah, it really is that simple, since specific overloads are tried before templates.
>
> --
>   Simen

Oh nice! So you don't even need all that mixin magic and can get away with:

struct A {
    void opAssign(int) {}
    @disable void opAssign(float) {}
    void opAssign(T)(T t) if (is(T == string)) {}
}

struct B(T) {
    A a;
    alias a this;
    @disable void opAssign(B!T);
    mixin(wrap!(B, "opAssign"));
}

string wrap(T, string methodName)() {
    enum targetName = __traits(getAliasThis, T)[0];
    return `auto `~methodName~`(T...)(T args)
        if (__traits(compiles, `~targetName~`.`~methodName~`(args))) {
        return `~targetName~`.`~methodName~`(args);
    }`;
}

void main() {
    B!int b;
    b = 3;
    b = "hello";
    static assert(!__traits(compiles, { b = 3f; } ));
    static assert(!__traits(compiles, { b = b; } ));
}




1 2
Next ›   Last »