digitalmars.D - static vs. dynamic interfaces
- Trass3r (11/11) Dec 28 2011 phobos currently checks "static interfaces" with something like
- Trass3r (1/1) Jan 03 2012 bump
- Philippe Sigaud (122/123) Jan 03 2012 It's possible alright. The only difficulty is in getting all overloads
phobos currently checks "static interfaces" with something like https://github.com/D-Programming-Language/phobos/blob/master/std/range.d#L213 I wonder if stuff like that could be unified by only defining normal interfaces and "automating" the static checking with something like template implements(T, I) if (is(I == interface)) { enum implements = is(typeof({foreach(t;__traits(allMembers,I)) // check T})); } Possible? Reasonable?
Dec 28 2011
Hi Trass3r: On Tue, Jan 3, 2012 at 13:52, Trass3r <un known.com> wrote:bumpIt's possible alright. The only difficulty is in getting all overloads of a given member resolved. This is what the AllMembers template gets (see below). It works on all aggregates (structs, classes, modules), for fields, aliases and methods. import std.typetuple; /** * Stores a member description as a name-Type pair */ struct Member(string n, T) { enum name = n; // for external access alias T Type; } /** * Helper template */ template MakeMember(alias member) { alias Member!(__traits(identifier, member), typeof(member)) MakeMember; } /** * Helper template to make is(__traits()) compile. Bug? */ template Alias(alias a) { alias a Alias; } /** * Gets the overloads of a given member, as a Member type tuple. */ template Overloads(alias a, string member) { static if (__traits(getOverloads, a, member).length > 0) // Method alias staticMap!(MakeMember, __traits(getOverloads,a, member)) Overloads; else // field or alias static if (is(typeof(__traits(getMember, a, member)))) // Field or symbol alias alias TypeTuple!(Member!(member, typeof(__traits(getMember, a, member)))) Overloads; else static if (is(Alias!(__traits(getMember, a, member)))) // Type alias alias TypeTuple!(Member!(member, __traits(getMember, a, member))) Overloads; else // template? alias TypeTuple!(Member!(member, void)) Overloads; } /** * Helper template, to be mapped in AllMembers. */ template GetOverloads(alias a) { template GetOverloads(string member) { alias Overloads!(a, member) GetOverloads; } } /** * Gives a list of all members, distinguishing between different overloads. * Gets the fields as well as the methods. */ template AllMembers(alias a) { alias staticMap!(GetOverloads!(a), __traits(allMembers, a)) AllMembers; } /** * Statically check if symbol a implements interface I * (that is, if all members of I are found in members of a) */ template implements(alias a, I) if (is(I == interface)) { alias implementsImpl!(a, AllMembers!I) implements; } template implementsImpl(alias a, Items...) { static if (Items.length == 0) enum implementsImpl = true; else static if (staticIndexOf!(Items[0], AllMembers!a) == -1) enum implementsImpl = false; else enum implementsImpl = implementsImpl!(a, Items[1..$]); } interface I { int foo(int i); void foo(); string toString(); } class Bad { void foo(int i) {} } /** * Show all examples I could think of */ struct Good { int field; int foo(int i) { return i;} void foo() { writeln("Hello, World!");} string toString() { return "I'm a good struct!";} alias double Type; alias field baz; template Id(T) { alias T Id;} } void main(string[] args) { assert(implements!(Good, I)); assert(!implements!(Bad, I)); foreach(elem; AllMembers!Good) writeln(elem.name, ", of type:", elem.Type.stringof); } I decided to give templates a void type. That's a bit arbitrary. Also, internal unit tests are not managed correctly, though they are members and should appear in an AllMembers list. But I find this a bit limitating. With interfaces, you can imitate isInputRange, but not isForwardRange (no way to test for assignments), nor isRandomAccessRange, no field access... The way it's done in Phobos seems much more powerful to me. Philippe
Jan 03 2012