Build interface from abstract class

DigitalDesigns DigitalDesigns at gmail.com
Wed May 30 12:16:53 UTC 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.



More information about the Digitalmars-d-learn mailing list