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.