Thread overview
Extensions to types loaded from a C library
Dec 14, 2012
Jeremy DeHaan
Dec 14, 2012
simendsjo
Dec 14, 2012
Mike Parker
Dec 14, 2012
Jacob Carlborg
Dec 14, 2012
Jeremy DeHaan
Dec 15, 2012
Jeremy DeHaan
Dec 15, 2012
Jacob Carlborg
Dec 14, 2012
Jacob Carlborg
December 14, 2012
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!
December 14, 2012
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.
December 14, 2012
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.
December 14, 2012
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
December 14, 2012
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
December 14, 2012
>
> 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!


December 15, 2012
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.

December 15, 2012
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