www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Extensions to types loaded from a C library

reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
I was playing with some code in the Derelict project(mainly the 
SFML portion) and was wondering what would happen if I made some 
changes.

Here's an example of what I mean.
In the C code, the struct sfVector2f is defined as such:

typedef struct
{
     float x;
     float y;
} sfVector2f;

The D version of this when loading the .dll into the application 
would be like this:

struct sfVector2f
{
     float x;
     float y;
}

And to my understanding, defining this allows us to use this 
structure in our calls to the C functions in the .dll. But then I 
thought, "could I maybe make some things easier?" and proceeded 
to experiment a bit. Right now I have the structure looking like 
this:

struct sfVector2f
{
     float x;
     float y;
	
	this(float X, float Y)
	{
		x = X;
		y = Y;
	}
}

This compiles just fine, and I can even use the constructor to 
create the object with seemingly no problems. But is this safe to 
do? My gut tells me yes, but I would rather make sure before I 
cause something to explode unknowingly!
Dec 14 2012
next sibling parent "simendsjo" <simendsjo gmail.com> writes:
On Friday, 14 December 2012 at 09:30:50 UTC, Jeremy DeHaan wrote:
 I was playing with some code in the Derelict project(mainly the 
 SFML portion) and was wondering what would happen if I made 
 some changes.

 Here's an example of what I mean.
 In the C code, the struct sfVector2f is defined as such:

 typedef struct
 {
     float x;
     float y;
 } sfVector2f;

 The D version of this when loading the .dll into the 
 application would be like this:

 struct sfVector2f
 {
     float x;
     float y;
 }

 And to my understanding, defining this allows us to use this 
 structure in our calls to the C functions in the .dll. But then 
 I thought, "could I maybe make some things easier?" and 
 proceeded to experiment a bit. Right now I have the structure 
 looking like this:

 struct sfVector2f
 {
     float x;
     float y;
 	
 	this(float X, float Y)
 	{
 		x = X;
 		y = Y;
 	}
 }

 This compiles just fine, and I can even use the constructor to 
 create the object with seemingly no problems. But is this safe 
 to do? My gut tells me yes, but I would rather make sure before 
 I cause something to explode unknowingly!
As far as I know, this should be perfectly safe, and is exactly what derelict (and every other binder library) does. If you try to add additional fields, it wont work though.. You might consider using alias this instead: struct Vector2f { sfVector2f vec; this(float x, float y) { vec.x = x; vec.y = y; } alias vec this; } This way Vector2f is implicitly converted to sfVector2f whenever needed, and you can add additional fields to your struct.
Dec 14 2012
prev sibling next sibling parent reply "Mike Parker" <aldacron gmail.com> writes:
On Friday, 14 December 2012 at 09:30:50 UTC, Jeremy DeHaan wrote:
 I was playing with some code in the Derelict project(mainly the 
 SFML portion) and was wondering what would happen if I made 
 some changes.

 Here's an example of what I mean.
 In the C code, the struct sfVector2f is defined as such:

 typedef struct
 {
     float x;
     float y;
 } sfVector2f;

 The D version of this when loading the .dll into the 
 application would be like this:

 struct sfVector2f
 {
     float x;
     float y;
 }

 And to my understanding, defining this allows us to use this 
 structure in our calls to the C functions in the .dll. But then 
 I thought, "could I maybe make some things easier?" and 
 proceeded to experiment a bit. Right now I have the structure 
 looking like this:

 struct sfVector2f
 {
     float x;
     float y;
 	
 	this(float X, float Y)
 	{
 		x = X;
 		y = Y;
 	}
 }

 This compiles just fine, and I can even use the constructor to 
 create the object with seemingly no problems. But is this safe 
 to do? My gut tells me yes, but I would rather make sure before 
 I cause something to explode unknowingly!
With D's UFCS syntax, there's really no need to modify Derelict directly to extend a C struct. http://www.gamedev.net/blog/1140/entry-2254754-uniform-function-call-syntax-in-d/ Obviously, this technique won't work for constructors, but it should work for most any other method you'd like to add. And I don't see a need to add a constructor anyway except in very specific circumstances (i.e. you want a constructor with fewer or more params, or different types, than the number or type of struct fields). And even then it's only a convenience.
Dec 14 2012
next sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-14 13:36, Mike Parker wrote:

 Obviously, this technique won't work for constructors, but it should
 work for most any other method you'd like to add. And I don't see a need
 to add a constructor anyway except in very specific circumstances (i.e.
 you want a constructor with fewer or more params, or different types,
 than the number or type of struct fields). And even then it's only a
 convenience.
No need for a constructor if you want fewer arguments: struct Foo { int a; int b; } auto f = Foo(3); -- /Jacob Carlborg
Dec 14 2012
prev sibling parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
 With D's UFCS syntax, there's really no need to modify Derelict 
 directly to extend a C struct.

 http://www.gamedev.net/blog/1140/entry-2254754-uniform-function-call-syntax-in-d/

 Obviously, this technique won't work for constructors, but it 
 should work for most any other method you'd like to add. And I 
 don't see a need to add a constructor anyway except in very 
 specific circumstances (i.e. you want a constructor with fewer 
 or more params, or different types, than the number or type of 
 struct fields). And even then it's only a convenience.
Wow, that is awesome! I think I can definitely make use of that! By the way, I thought I should mention that I wasn't suggesting Derelict needed to be modified. It was just what I had to experiment with. ;) And thanks to everyone else that gave me answers!
Dec 14 2012
parent reply "Jeremy DeHaan" <dehaan.jeremiah gmail.com> writes:
Just thought I should give an update. After testing a little bit, 
I found out that it is not safe in some situations.

With the code looking like this:

struct sfVector2f
{
     float x;
     float y;
	
	this(float X, float Y)
	{
		x = X;
		y = Y;
	}
}


The following does not work right:

sfSprite* sprite;

sprite = sfSprite_create();

sfVector2f originalLocation = sfSprite_getPosition(sprite);

writeln("Original ", originalLocation.x, " ", originalLocation.y);

sfVector2f newPosition = sfVector2f(100,200);

sfSprite_setPosition(sprite, newPosition);

sfVector2f returnedPosition = sfSprite_getPosition(sprite);
	
writeln("Output ", returnedPosition.x, " ", returnedPosition.y);


And outputs the following:

Original 1.4013e-44 4.12947e-39
Output 0 6.04679e-39


But when changed back to:
struct sfVector2f
{
     float x;
     float y;
}

The above code works as expected:
Original 0 0
Output 100 200



Thus it appears that any extensions made to the types defined in 
a C library is not safe! Even one as trivial as a constructor. I 
didn't show the code or output(it was with some different tests), 
but I also got some run time errors when using the version of 
sfVector2f at the top which went away when I changed it back to 
the original code.


On a different note, this site could REAAAAALLLYY use some sort 
of way to format code.
Dec 14 2012
parent Jacob Carlborg <doob me.com> writes:
On 2012-12-15 07:26, Jeremy DeHaan wrote:

 Thus it appears that any extensions made to the types defined in a C
 library is not safe! Even one as trivial as a constructor. I didn't show
 the code or output(it was with some different tests), but I also got
 some run time errors when using the version of sfVector2f at the top
 which went away when I changed it back to the original code.
For that simple constructor there is no need to defined one. This works just as good: struct sfVector2f { float x; float y; } sfVector2f newPosition = sfVector2f(100,200); -- /Jacob Carlborg
Dec 15 2012
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2012-12-14 10:30, Jeremy DeHaan wrote:
 I was playing with some code in the Derelict project(mainly the SFML
 portion) and was wondering what would happen if I made some changes.
As long as the size of the struct doesn't change it's ok. Preferably you shouldn't change the type or ordering of the fields either. -- /Jacob Carlborg
Dec 14 2012