Thread overview | ||||||||
---|---|---|---|---|---|---|---|---|
|
November 11, 2014 passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
* 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. } |
November 12, 2014 Re: passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam Taylor | 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{
/+...+/
}
----
|
November 12, 2014 Re: passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
Posted in reply to Freddy | > 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.
|
November 12, 2014 Re: passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam Taylor | > 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); } |
November 12, 2014 Re: passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam Taylor | 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.... |
November 13, 2014 Re: passing duck-typed objects and retaining full type information | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam Taylor | 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 approach. Generics in C# allow for this, which I believe is 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.
|
Copyright © 1999-2021 by the D Language Foundation