Build interface from abstract class

Simen Kjærås simen.kjaras at gmail.com
Wed May 30 10:31:27 UTC 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


More information about the Digitalmars-d-learn mailing list