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