passing duck-typed objects and retaining full type information

Adam Taylor via Digitalmars-d-learn digitalmars-d-learn at puremagic.com
Tue Nov 11 11:23:38 PST 2014


* 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.
}


More information about the Digitalmars-d-learn mailing list