Steven Schveighoffer wrote: >On Sat, 09 Jul 2011 05:47:51 -0400, Johannes Pfau <s...@example.com> >wrote: > >> Hi, >> >> I have a wrapper for a "object aware" c library (cairo). Take for >> example two classes, Surface and a subclass, ImageSurface. Now this >> code has to be valid: >> ----------------------- >> auto ptr = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 512, 512); >> Surface s = new Surface(ptr); >> ImageSurface imgs = cast(ImageSurface)s; >> ----------------------- >> >> As D cannot know that 's' really should be an ImageSurface, I have >> implemented opCast to get this example working: >> ----------------------- >> class Surface >> { >> static Surface castFrom(Surface other) >> { >> return other; >> } >> T opCast(T)() if(isImplicitlyConvertible!(T, Surface)) >> { >> return T.castFrom(this); >> } >> } >> class ImageSurface : Surface >> { >> static ImageSurface castFrom(Surface other) >> { >> auto type = cairo_surface_get_type(other.nativePointer); >> if(type == cairo_surface_type_t.CAIRO_SURFACE_TYPE_IMAGE) >> { >> return new ImageSurface(other.nativePointer); >> } >> else >> return null; >> } >> } >> ----------------------- >> >> This code works quite well. But it performs unnecessary calls to >> cairo_surface_get_type (and allocates unnecessary objects) for simple >> cases: >> ----------------------- >> auto surface = new ImageSurface(Format.CAIRO_FORMAT_ARGB32, 400, >> 400); Surface tmp = cast(Surface)surface; >> ImageSurface test = cast(ImageSurface)as; >> ----------------------- >> >> In this case, the first D object already is an ImageSurface so the >> custom opCast code isn't needed for the last line. >> >> So the question is: Is there some way to check in the opCast function >> if a normal D object cast would succeed and then just return it's >> result? > >I think a factory method would work well here. > >If you have a finite set of classes you are creating, a factory method >can simply use a switch on the cairo_surfase_type, and you could even >put it in Surface: > >auto s = Surface.create(ptr); // automatically creates the correct >derived class. > >Then use dynamic cast to get to the expected derived class. > >If you do not have a finite set of classes, you may be able to use >runtime type info (a la object.factory). But from your example, it >seems like cairo defines an enum which encapsulates all classes. > >Another option, judging from your code, if cairo's functions to >create surface objects are specific to the derived type (i.e. >cairo_image_surface_create => ImageSurface), then you could simply >wrap the cairo functions. Basically avoid calling the C creation >routines outside the D class constructors. > >-Steve
Thanks for answering. I already use such a factory method (called createFromNative). I also create the correct D objects if the Surfaces are created from D as in your second suggestion (I still need createFromNative, as there are methods like cairo_pattern_get_surface which receive Surfaces from cairo). Thinking about it the whole opCast stuff is indeed obsolete as long as all code correctly calls createFromNative. I first wanted to make it possible to add Surface wrappers outside of cairoD, but I dropped that idea. Without that feature a factory method should be enough. -- Johannes Pfau