C#'s greatest mistakes

Jonathan M Davis jmdavisProg at gmx.com
Sat Nov 27 17:06:32 PST 2010


On Saturday 27 November 2010 16:18:00 BLS wrote:
> On 28/11/2010 00:19, Jonathan M Davis wrote:
> > On Saturday 27 November 2010 14:59:09 BLS wrote:
> >> On 27/11/2010 16:59, Torarin wrote:
> >>> 2010/11/27 Andrei Alexandrescu<SeeWebsiteForEmail at erdani.org>:
> >>>> We use template constraints for that kind of stuff.
> >>>> 
> >>>> Andrei
> >>> 
> >>> Yes, and that's great, but is there a way to check whether a template
> >>> argument matches a defined interface?
> >> 
> >> I could not resist..
> >> We should have Implements!
> >> 
> >> Luca has done some work on it.. but it does not compile anymore. However
> >> I think the intension is clear.
> >> http://www.digitalmars.com/webnews/newsgroups.php?art_group=digitalmars.
> >> D&a rticle_id=101673
> > 
> > If you're checking whether it implements an interface, then : should work
> > just like it does with classes. If you're checking whether it has the
> > same functions that an interface requires, then you're not really using
> > interfaces correctly. structs don't implement interfaces. Classes do
> > that. So, either make it a class, or don't use interfaces. If you want
> > to verify that a struct has particular functions needed for the template
> > function in question, then just check whether calling them compiles (
> > e.g. __traits(compiles, foo.bar()) ). If you have a set of functions
> > that are expected to be there (for instance, to verify that the given
> > type is a certain type of range), then just create template which checks
> > for each of the functions that are supposed to be there and use the
> > template ( e.g. isForwardRange!T ). Interfaces and structs don't have
> > anything to do with each other.
> > 
> > - Jonathan M Davis
> 
> Thanks for taking the time to explain. I've copypasted.
> However,
> Given that dCollections enable me to change the underlaying algorithm
> (say I can replace the default RBTree with SkipList) In order to so that
> I have to fulfil some requirements. And now, I guess that is what I am
> talking about. I want a guarantee that my skiplist implementation
> fulfills the cursor (a structure) requirements.
> 
> So now what is wrong with the contract from dCollections I am asking
> for. Please note that dCollections implements cursors as well as ranges.

Interfaces are class-based. Only classes can implement them. It makes no sense 
to use an interface with structs, because you can't do it. If you're using 
interfaces with a template, then you simply verify that the type implements the 
interface in question. You should be able to use : exactly in the same manner 
that you'd use it to check that a class is a particular type or is derived from 
a that type.

On the other hand, if you're using structs, then the only way that you're going 
to be able to interchange them based on an API is with templates. A struct 
cannot implement an interface. So, it makes no sense to talk about a struct 
implementing one. If you want to ensure that a type that is used to instantiate 
a template has a certain API, then you verify that in the template constraint, 
and the way to do that in a manner which is reusable is to use a template which 
verifies that the type has every function that it's supposed to have. You then 
use that template in the template constraint. The range templates such as 
IsForwardRange!() and isInputRang!e() are prime examples of that.

You could theoretically create a template which verified that a struct had the 
same functions that an interface required for a class to implement it, but since 
a struct can't implement it, it's just confusing and unnecessary to add a 
useless interface into the mix. The struct can't implement it.

And if you you're using a class instead of struct, then the template should 
verify that the type implements the interface. And if it's templated simply on 
the type, then you probably don't even need a template - just use the interface 
itself directly.

I don't know exactly what DCollections does. But it's using the language to do 
whatever it's doing.  So, if it's an interface that you need, you have to be 
using classes, and you can have template constraints verify that the type 
implements the template. structs never will, so they'll fail the constraint.

If, on the other hand, you need to match a particular API - no interfaces 
involved - then it's going to be a template, and then any template constraints 
need to verify that whatever functions the template requires are present on the 
type. No interfaces are involved.

Really, if you're trying to have a struct implement an interface (as opposed to 
an API), then you're misunderstanding how interfaces work.

- Jonathan M Davis


More information about the Digitalmars-d mailing list