passing duck-typed objects and retaining full type information

Freddy via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Nov 11 17:21:03 PST 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{
      /+...+/
}
----


More information about the Digitalmars-d-learn mailing list