May 30, 2018
On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:
> I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means.
>
> 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again.
>
> 2. Your method of function creation does not pick up attributes and other factors so it is weak.
>
> Here is my solution that does not solve problem 2:
>
> [Neat stuff]

Neat, but as you say it doesn't handle attributes or UDAs. The use of stringof is also a red flag - the same name can apply to different types in different scopes, and aliases may confuse it. Here's a version that solves both of those issues:


import std.array : join;
import std.meta : ApplyLeft, staticMap, Filter, Alias;
import std.traits;

enum isPublic(alias overload) = Alias!(__traits(getProtection, overload) == "public");

interface InterfaceFromClass(T, alias filter = isPublic)
{
    static foreach (overload; Filter!(filter, staticMap!(ApplyLeft!(MemberFunctionsTuple, T), __traits(derivedMembers, T))))
        mixin("@(__traits(getAttributes, overload)) "~attributes!overload~" ReturnType!overload "~__traits(identifier, overload)~"(Parameters!overload);");
}

string attributes(alias overload)()
{
    enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, overload),
        "pure", "nothrow", "ref", "@property", "@trusted", "@safe", "@nogc", "@system", "const", "immutable", "inout", "shared", "return", "scope");
    return [attrs].join(" ");
}

alias A = InterfaceFromClass!C;

abstract class C : A
{
    int n;
    @("InterfaceMembers")
    {
        @(3) ref int foo(ref int a) { return n; }
        @(19) @safe void bar() { }
    }
}

// https://issues.dlang.org/show_bug.cgi?id=18915
// class D : C {}

static assert([__traits(allMembers, A)] == ["foo", "bar"]);
static assert(functionAttributes!(A.foo) == functionAttributes!(C.foo));
static assert(functionAttributes!(A.bar) == functionAttributes!(C.bar));
static assert(is(Parameters!(A.foo) == Parameters!(C.foo)));
static assert(is(Parameters!(A.bar) == Parameters!(C.bar)));

Note the link to issue 18915 (that's your 'string mixin output works...' post). I believe if we can fix that, the above should work.

--
  Simen
May 30, 2018
On Wednesday, 30 May 2018 at 10:31:27 UTC, Simen Kjærås wrote:
> On Monday, 28 May 2018 at 20:13:49 UTC, DigitalDesigns wrote:
>> I do not think this is a problem in D. Infinite recursion can always be terminated with appropriate means.
>>
>> 1. Use attributes. methods in class A should be marked as being for the interface. When added to the interface they will not have the attribute so will not be picked up again.
>>
>> 2. Your method of function creation does not pick up attributes and other factors so it is weak.
>>
>> Here is my solution that does not solve problem 2:
>>
>> [Neat stuff]
>
> Neat, but as you say it doesn't handle attributes or UDAs. The use of stringof is also a red flag - the same name can apply to different types in different scopes, and aliases may confuse it. Here's a version that solves both of those issues:
>
>
> import std.array : join;
> import std.meta : ApplyLeft, staticMap, Filter, Alias;
> import std.traits;
>
> enum isPublic(alias overload) = Alias!(__traits(getProtection, overload) == "public");
>
> interface InterfaceFromClass(T, alias filter = isPublic)
> {
>     static foreach (overload; Filter!(filter, staticMap!(ApplyLeft!(MemberFunctionsTuple, T), __traits(derivedMembers, T))))
>         mixin("@(__traits(getAttributes, overload)) "~attributes!overload~" ReturnType!overload "~__traits(identifier, overload)~"(Parameters!overload);");
> }
>
> string attributes(alias overload)()
> {
>     enum attrs = Filter!(ApplyLeft!(hasFunctionAttributes, overload),
>         "pure", "nothrow", "ref", "@property", "@trusted", "@safe", "@nogc", "@system", "const", "immutable", "inout", "shared", "return", "scope");
>     return [attrs].join(" ");
> }
>
> alias A = InterfaceFromClass!C;
>
> abstract class C : A
> {
>     int n;
>     @("InterfaceMembers")
>     {
>         @(3) ref int foo(ref int a) { return n; }
>         @(19) @safe void bar() { }
>     }
> }
>
> // https://issues.dlang.org/show_bug.cgi?id=18915
> // class D : C {}
>
> static assert([__traits(allMembers, A)] == ["foo", "bar"]);
> static assert(functionAttributes!(A.foo) == functionAttributes!(C.foo));
> static assert(functionAttributes!(A.bar) == functionAttributes!(C.bar));
> static assert(is(Parameters!(A.foo) == Parameters!(C.foo)));
> static assert(is(Parameters!(A.bar) == Parameters!(C.bar)));
>
> Note the link to issue 18915 (that's your 'string mixin output works...' post). I believe if we can fix that, the above should work.
>
> --
>   Simen

Yeah! with a little work you can include fields in the interfacemembers because they will be ignored.

I see no reason to have to declare an interface in D except in rare occasions! One should be able to abstract out an interface from a class or abstract class and use it as the base only for others to use. If a program was "sealed" there would be no real point in using interfaces(assuming it was designed to perfection) except to get around the diamond problem, which is what interfaces solve but in the process have forced us to duplicate code.

The above technique alleviates that problem greatly. It's still bring the members inside the interface because it allows one to add final, static, and normal members if desired, although, this can be done by using another interface and inheriting from that.

1 2
Next ›   Last »