June 14, 2017
On Wednesday, 14 June 2017 at 09:34:27 UTC, Balagopal Komarath wrote:
> Why doesn't this work? The Test!Duck type has a void quack() method but the compiler says it is not implemented.
>
> import std.stdio;
>
> interface IDuck
> {
>     void quack();
> }
>
> class Test(T) : IDuck
> {
>     T data;
>     alias data this;
> }
>
> struct Duck
> {
>     void quack()
>     {
>         writeln("Quack");
>     }
> }
>
>
> void main()
> {
> 	Test!Duck d;
> }

The way to do that in D is with mixins:

interface IDuck
{
    void quack();
}

class Test(alias MyImpl) : IDuck
{
    mixin MyImpl;
}

mixin template DuckImpl()
{
    void quack()
    {
        import std.stdio;
        writeln("Quack Quack");
    }
}

void main()
{
    (new Test!DuckImpl).quack;
}
June 14, 2017
On Wednesday, 14 June 2017 at 21:04:55 UTC, basile b. wrote:
> The way to do that in D is with mixins:

That is an interesting solution.

However, my original goal was to figure out whether one can make struct types behave polymorphically (Which is not mentioned in my original question).  I know that this is not supported by design. I want to keep the original struct types but also allow functions to accept those struct types and do runtime dispatch. The following code should give a better idea by what I mean by this.

https://dpaste.dzfl.pl/051f6a4da059

The user need only define Duck1, Duck2 ... with appropriate functions and mixin toDuck. Then a function that accepts a Duck can accept DuckLike (for dynamic dispatch) or templatize on the type of Duck.
June 15, 2017
On Wednesday, 14 June 2017 at 22:29:08 UTC, Balagopal Komarath wrote:
> On Wednesday, 14 June 2017 at 21:04:55 UTC, basile b. wrote:
>> The way to do that in D is with mixins:
>
> That is an interesting solution.
>
> However, my original goal was to figure out whether one can make struct types behave polymorphically (Which is not mentioned in my original question).  I know that this is not supported by design. I want to keep the original struct types but also allow functions to accept those struct types and do runtime dispatch. The following code should give a better idea by what I mean by this.
>
> https://dpaste.dzfl.pl/051f6a4da059
>
> The user need only define Duck1, Duck2 ... with appropriate functions and mixin toDuck. Then a function that accepts a Duck can accept DuckLike (for dynamic dispatch) or templatize on the type of Duck.

Duck typing doesn't work with the pattern you used initially.
The pattern you used initially is much more similar to the solution i exposed.

The point is that "alias" cant do what you wished.
It's not in the language, end of story.

Finally duck types in D are more like this:

enum looksLikeaDuck(T) = __traits(hasMember, T, "quack");

class Test(T)
if (looksLikeaDuck!T)
{
    T data;
    alias data this;
}

struct Duck
{
    void quack()
    {
        import std.stdio;
        writeln("Quack");
    }
}

void main()
{
    Test!Duck d;
}

you use traits to verify that the template parameter looks like a duck.
It's not like in Swift where an aggregate is used.
In D we use traits (even if traits can be used to verify that a template parameter is compliant with the member of an aggregate).
June 15, 2017
On Wednesday, 14 June 2017 at 09:34:27 UTC, Balagopal Komarath wrote:
> void main()
> {
> 	Test!Duck d;
> }

As has been pointed out at length by others here, it's simply not how alias this is intended to work. I do see some arguments in favor of working that way, but I'm not sure what's the right solution.

Anyways, there is another solution - we could write a template that does the conversion for us. There is std.typecons.Proxy, which seems like a good fit, however it doesn't work quite the way we want. Here however, is a solution that works for simple examples. It might work for more complex examples as well, but I simply haven't tested that:

template duckImpl(alias a, TI, Fns...) {
    static if (Fns.length > 0) {
        mixin duckImpl!(a, TI, Fns[1..$]);

        alias thisFn = Fns[0];
        enum string fnName = __traits(identifier, thisFn);

        mixin("ReturnType!thisFn "~fnName~"(Parameters!thisFn args) { return a."~fnName~"(args); }");
    }
}

template duck(TI) if (is(TI == interface)) {
    TI duck(T)(T t) {
        import std.meta;
        import std.traits;

        template Functions(string s) {
            alias Functions = MemberFunctionsTuple!(TI, s);
        }

        static class Result : TI {
            private T payload;
            this(T value) {
                payload = value;
            }
            mixin duckImpl!(payload, TI, staticMap!(Functions, __traits(allMembers, TI)));
        }
        return new Result(t);
    }
}

interface I {
    void bar();
}

struct S {
    void bar() {
        import std.stdio;
        writeln("OHAI");
    }
}

unittest {
    I i = S().duck!I;
    i.bar();
}

--
  Biotronic
June 15, 2017
On Thursday, 15 June 2017 at 07:12:56 UTC, Biotronic wrote:
> Here however, is a solution that works for simple examples.


This is awesome. Very generic. Thanks.
June 15, 2017
On Wednesday, 14 June 2017 at 09:34:27 UTC, Balagopal Komarath wrote:
> Why doesn't this work? The Test!Duck type has a void quack() method but the compiler says it is not implemented.

You question was answered, but you can do this:

------------------
    interface IDuck
    {
        void quack();
    }

    struct Duck
    {
        void quack()
        {
    		import std.stdio : writeln;
            writeln("Quack");
        }
    }


    void main()
    {
    	Duck d;
    	import std.experimental.typecons : wrap;
    	IDuck i = wrap!IDuck(d);
    	i.quack();
    }
-----------------

Please note that you can't wrap to an interface which returns itself

interface IDuck {
    IDuck clone();
}

It fails because the struct would return a Duck and wouldn't wrap it to an IDuck. This is only a limitation on wrap because I haven't written the detection and appropriate wrapping function call.
June 16, 2017
On Thursday, 15 June 2017 at 18:49:58 UTC, Jesse Phillips wrote:
> wrap!IDuck

Ah, so it does exist in Phobos. I thought it should be there, but didn't find it. Thanks!

--
  Biotronic
June 16, 2017
On Friday, 16 June 2017 at 08:34:21 UTC, Biotronic wrote:
> On Thursday, 15 June 2017 at 18:49:58 UTC, Jesse Phillips wrote:
>> wrap!IDuck
>
> Ah, so it does exist in Phobos. I thought it should be there, but didn't find it. Thanks!
>
> --
>   Biotronic

Yeah, when Andrei introduced the wrap function I was disappointed it only wrapped classes. But in truth I haven't really been using it for structs either. That may partly be because it can't wrap to the range interface.
1 2
Next ›   Last »