digitalmars.D.learn - opCast, c bindings and normal casts.
- Johannes Pfau (53/53) Jul 09 2011 Hi,
- Johannes Pfau (8/59) Jul 12 2011 In case anyone's interested:
- Steven Schveighoffer (17/67) Jul 12 2011 I think a factory method would work well here.
- Johannes Pfau (13/86) Jul 12 2011 Thanks for answering.
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? -- Johannes Pfau
Jul 09 2011
Johannes Pfau 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?In case anyone's interested: I think this could be done with _d_dynamic_cast from rt.cast_ (druntime). I've dropped the opCast/castFrom approach though (not working in some cases), so I haven't tested this. -- Johannes Pfau
Jul 12 2011
On Sat, 09 Jul 2011 05:47:51 -0400, Johannes Pfau <spam 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
Jul 12 2011
Steven Schveighoffer wrote:On Sat, 09 Jul 2011 05:47:51 -0400, Johannes Pfau <spam example.com> wrote: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 PfauHi, 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
Jul 12 2011