On Monday, 28 May 2018 at 11:51:20 UTC, Simen Kjærås wrote:
On Monday, 28 May 2018 at 09:59:50 UTC, DigitalDesigns wrote:
Implementing interfaces can be a pain but are necessary.

I like to use abstract classes and provide a base implementation. It would be cool if I could use D's awesome meta features to extract the interface from the abstract class then build it. This requires some funky stuff which I'm not sure D can do

Creating an interface based on a class is no big deal in D:

interface Interface(T)
{
    import std.traits;
    static foreach (fn; __traits(allMembers, T))
        static foreach (overload; MemberFunctionsTuple!(T, fn))
mixin("ReturnType!overload "~fn~"(Parameters!overload);");
}

class A
{
   void fun() {}
}

alias IA = Interface!A;

However, you run into a problem when A is expected to implement IA: in order to figure out which functions should be in the interface, we need to know which functions are in A. And in order to figure out which functions are in A, we need to know which functions are in IA. It's a loop with no real solution.

In this specific case, one could consider only members of A, ignoring any interfaces or base classes. This isn't currently possible, but it's not an entirely unreasonable enhancement request.

--
  Simen

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.


Case 1 should be easy to deal with. Case 2, I am not so sure how to build the signature exactly as it is expressed. This is, of course, just a copy an paste mechanism but it would require D to provide us the signature in some way.

Maybe an easy and direct way would be to pass __FILE__ and __LINE__ and extract the line? This seems a bit risky and slow.

Case 1 Will not work if UDA's are required to be exactly the same between interface and class. I do not know if D enforces that but if it does it seems a bit overkill.


Here is my solution that does not solve problem 2:


import std.stdio;



template InterfaceFromClass(alias T, string id)
{
        auto InterfaceFromClass()
        {
                string s;
                import std.traits;
                foreach (member; __traits(allMembers, T))
                {
                        static foreach (overload; MemberFunctionsTuple!(T, 
member))
                        {
                                enum attr = __traits(getAttributes, overload);
static if (__traits(getProtection, __traits(getMember, T, member)) == "public")
                                {
mixin(`enum attrs = __traits(getAttributes, T.` ~ member ~ `);`);
                                        foreach(a; attrs)
static if (is(typeof(a) == string) && a.length > 0 && a == "InterfaceMembers")
                                                {                               
                                                
s ~= (ReturnType!overload).stringof ~" "~member~""~(Parameters!overload).stringof~";";
                                                }
                                }
                        }
                }

                return "interface "~id~"\n{\n "~s~"\n}";
        }
}



Which you can see it at work here: https://dpaste.dzfl.pl/f49be5dd7daa

Reply via email to