digitalmars.D.learn - passing duck-typed objects and retaining full type information
- Adam Taylor (101/101) Nov 11 2014 * i apologize in advance, this is my first post -- the code
- Freddy (11/113) Nov 11 2014 Not entirly sure of what you asking for,but have you tried
- Adam Taylor (4/14) Nov 11 2014 No, i'm specifically looking for a solution that is NOT
- Adam Taylor (12/16) Nov 11 2014 For example in this thread:
- Adam D. Ruppe (10/11) Nov 11 2014 What that does is defer the type work to runtime, so a lot of
- Jesse Phillips (9/16) Nov 12 2014 You can't. This is one of the major restrictions of the template
* i apologize in advance, this is my first post -- the code formatting probably wont turn out so great... I have a bunch of duck typed interfaces for "containers" similar to what you would find in std.range. i.e. template isContainer(C) { enum bool isContainer = is(typeof( (inout int = 0) { C c = C.init; ... })); } template canRemoveFromContainer(C) { enum bool canRemoveFromContainer = isContainer!C && is(typeof( (inout int = 0) { C c = C.init; c.remove(); })); } Now what i want to do is pass some such "container" object to an interface function: interface MyInterface { void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) } but of coarse templates and interfaces don't get along so well. so...so far as I know i would need to do something like this: interface MyInterface { final void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) { filterCollisionsImpl(...); } void filterCollisionsImpl(...) } and pass something to filterCollisionsImpl that is a "proper" class or interface type. So here's the problem: many of the "duck-typed" interfaces cannot be converted to proper interfaces without losing something. So is there ANY way to pass in a very basic class or interface Container type and call the remove function on it? Here's what i've tried: interface Container(C) { ... } template ContainerObject(C) if (isContainer!(Unqual!C)) { static if (is(C : Container!(ElementType!C))) { alias ContainerObject = C; } else static if (!is(Unqual!C == C)) { alias ContainerObject = ContainerObject!(Unqual!C); } else { static if (__traits(compiles, { enum e = C.ValueType; })) { alias ValueType = C.ValueType; } else { alias ValueType = ElementType!C; } class ContainerObject : Container!ValueType { C _container; this(C container) { this._container = container; } static if(canRemoveFromContainer!C) { size_t remove() { return _container.remove(); } } } } } ContainerObject!C containerObject(C)(C container) if (isContainer!C) { static if (is(C : Container!(ElementType!C))) { return container; } else { return new ContainerObject!C(container); } } interface MyInterface { final void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) { auto container = containerObject(collisionCandidates); container.remove(); // works just fine -- have the complete type info at instantiation site filterCollisionsImpl(); } void filterCollisionsImpl(Container!string collisionCandidates) collisionCandidates.remove(); // error -- some type info is lost here, only have a Container!string which doesn't have a remove function. }
Nov 11 2014
On Tuesday, 11 November 2014 at 19:23:39 UTC, Adam Taylor wrote:* i apologize in advance, this is my first post -- the code formatting probably wont turn out so great... I have a bunch of duck typed interfaces for "containers" similar to what you would find in std.range. i.e. template isContainer(C) { enum bool isContainer = is(typeof( (inout int = 0) { C c = C.init; ... })); } template canRemoveFromContainer(C) { enum bool canRemoveFromContainer = isContainer!C && is(typeof( (inout int = 0) { C c = C.init; c.remove(); })); } Now what i want to do is pass some such "container" object to an interface function: interface MyInterface { void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) } but of coarse templates and interfaces don't get along so well. so...so far as I know i would need to do something like this: interface MyInterface { final void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) { filterCollisionsImpl(...); } void filterCollisionsImpl(...) } and pass something to filterCollisionsImpl that is a "proper" class or interface type. So here's the problem: many of the "duck-typed" interfaces cannot be converted to proper interfaces without losing something. So is there ANY way to pass in a very basic class or interface Container type and call the remove function on it? Here's what i've tried: interface Container(C) { ... } template ContainerObject(C) if (isContainer!(Unqual!C)) { static if (is(C : Container!(ElementType!C))) { alias ContainerObject = C; } else static if (!is(Unqual!C == C)) { alias ContainerObject = ContainerObject!(Unqual!C); } else { static if (__traits(compiles, { enum e = C.ValueType; })) { alias ValueType = C.ValueType; } else { alias ValueType = ElementType!C; } class ContainerObject : Container!ValueType { C _container; this(C container) { this._container = container; } static if(canRemoveFromContainer!C) { size_t remove() { return _container.remove(); } } } } } ContainerObject!C containerObject(C)(C container) if (isContainer!C) { static if (is(C : Container!(ElementType!C))) { return container; } else { return new ContainerObject!C(container); } } interface MyInterface { final void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) { auto container = containerObject(collisionCandidates); container.remove(); // works just fine -- have the complete type info at instantiation site filterCollisionsImpl(); } void filterCollisionsImpl(Container!string collisionCandidates) collisionCandidates.remove(); // error -- some type info is lost here, only have a Container!string which doesn't have a remove function. }Not entirly sure of what you asking for,but have you tried inhertance? ---- interface Base(C){ /+...+/ } interface Derived(C):Base!C{ /+...+/ } ----
Nov 11 2014
Not entirly sure of what you asking for,but have you tried inhertance? ---- interface Base(C){ /+...+/ } interface Derived(C):Base!C{ /+...+/ } ----No, i'm specifically looking for a solution that is NOT inheritance based. I've been looking at solutions based on opDispatch or template mixins -- but so far haven't come up with anything.
Nov 11 2014
No, i'm specifically looking for a solution that is NOT inheritance based. I've been looking at solutions based on opDispatch or template mixins -- but so far haven't come up with anything.For example in this thread: http://forum.dlang.org/thread/mailman.410.1319536838.24802.digitalmars-d puremagic.com?page=2 Adam Ruppe has an interesting example: DynamicObject delegate(DynamicObject[] args) dynamicFunctions; DynamicObject opDispatch(string name, T...)(T t) { if(name !in dynamicFunctions) throw new MethodNotFoundException(name); DynamicObject[] args; foreach(arg; t) args ~= new DynamicObject(arg); return dynamicFunctions[name](args); }
Nov 11 2014
On Wednesday, 12 November 2014 at 01:50:07 UTC, Adam Taylor wrote:Adam Ruppe has an interesting example:What that does is defer the type work to runtime, so a lot of type information is lost there too. The big magic is that the wrapper object is a template, specialized for the compile time type, but once it is used it is still through an interface. This is similar to how the inputRangeObject+InputRange interface work in phobos http://dlang.org/phobos/std_range.html#inputRangeObject Plain interface, templated implementation. I don't really understand your question though....
Nov 11 2014
On Tuesday, 11 November 2014 at 19:23:39 UTC, Adam Taylor wrote:Now what i want to do is pass some such "container" object to an interface function: interface MyInterface { void filterCollisions(S)(S collisionCandidates) if(canRemoveFromContainer!S) }You can't. This is one of the major restrictions of the template reliant its JIT compiler. Once you introduce the need for a vTable (which interfaces do) it is no longer possible to require implementation of a "phantom" function. Templates don't exist until their use, so it is not possible to require an entry in the vTable when the number of possible combinations is infinite.
Nov 12 2014