Re: opCast, c bindings and normal casts.

2011-07-12 Thread Johannes Pfau
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



Re: opCast, c bindings and normal casts.

2011-07-12 Thread Steven Schveighoffer

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


Re: opCast, c bindings and normal casts.

2011-07-12 Thread Johannes Pfau
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