opCast, c bindings and normal casts.

Johannes Pfau spam at example.com
Tue Jul 12 06:27:42 PDT 2011


Steven Schveighoffer wrote:
>On Sat, 09 Jul 2011 05:47:51 -0400, Johannes Pfau <spam at 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



More information about the Digitalmars-d-learn mailing list