SFML community forums

General => Feature requests => Topic started by: rogerlevy on December 22, 2010, 04:05:20 pm

Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 04:05:20 pm
I'm using a language (Forth) that has no clue about passing structs by value - it was a chore enough to create working bindings for SFML , then I had to convert the arguments to pass-by-reference for it to work properly and not have to worry if the structs change in the future.  I was wondering if it might hurt to make these (few?) functions to all use call-by-reference?  I know it seems silly to do it just for one person but I like SFML and if I ever update to 2.0 (currently using 1.6) then I'm just concerned I might have to modify the source heavily.  I know that using call-by-value is faster but so far the routines I converted like sfWindow_Create weren't performance-critical.  So what do you say?  Can you accomodate me?  I could contribute my modified source to SVN...
Title: Call and return by reference in CSFML
Post by: Groogy on December 22, 2010, 04:20:35 pm
I might misunderstand but you want to write bindings for Forth?

Anyway I wrote the bindings for Ruby and it's the same, every variable is a reference to an object and nothing is passed by value. What I did was to allocate everything on the heap whenever I wanted an object from SFML and it was fixed.

Example:
Code: [Select]

window = SFML::Window.new

The code in C/C++ run here is actually:
Code: [Select]
static VALUE Window_New( int argc, VALUE *args, VALUE aKlass )
{
sf::Window *object = new sf::Window(); // <- This is the interesting part
VALUE rbData = Data_Wrap_Struct( aKlass, 0, Window_Free, object );
rb_obj_call_init( rbData, argc, args );
return rbData;
}


Why it would be a bad idea to make everything use reference(in C that's simply pointers) is because it's pointers. We want to avoid that as it's more error-prone.
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 04:24:32 pm
You mean that Forth can import and use C libraries, but only support primitive types (numbers and pointers) in C function calls? This is pretty weird. It makes the language incompatible with many C libraries.

Anyway, I'm sorry but I'm not going to make the C API a little more complicated to use, just for the sake of having a Forth binding.

Groogy > I assume he's talking about functions arguments, not objects instances.
Title: Call and return by reference in CSFML
Post by: Groogy on December 22, 2010, 04:30:34 pm
Quote from: "Laurent"

Groogy > I assume he's talking about functions arguments, not objects instances.


Then it is more something like:
Code: [Select]

sf::Drawable *drawable = NULL;
Data_Get_Struct( args[0], sf::Drawable, drawable );
window->Draw( *drawable );


The previous does solve it, if we allocate everything on the heap for the binding then automatically we have to work with everything as references. And when we pass them on to SFML we just dereference them.

But well, I might be all wrong and misunderstood what he meant.
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 04:54:52 pm
I think he's talking about this kind of function
Code: [Select]
CSFML_API sfWindow* sfWindow_Create(
    sfVideoMode Mode, // pass by value
    const char* Title,
    unsigned long Style,
    sfWindowSettings Params // pass by value
);


You have no problem with Ruby because you write the binding in C++. I assume he's writing it directly in Forth, and thus is limited on its calls to C functions.

But I might as well completely misunderstood ;)
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 05:57:49 pm
Laurent, that's right, I only have the ability to use the C functions in Forth.  

I've already written about 80% of the bindings, that isn't the problem at all because they can be fairly easily converted from the .H files.  Passing by value when the structure is more than 32-bits is problematic because the DLL-interface assumes that most parameters are exactly 32-bits. (To do 64-bits, I have to literally put two parameters instead of one.)

In theory, I could cook up a way to automatically tell Forth to allocate space for the structs on the parameter stack, but that would be extremely awkward and not reliable.  Forth is simpler than C in the backend (to the advantage of lightning-quick compilation.) so it isn't really strange I'd say, just ... primitive.
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 07:09:05 pm
Would you be able to quickly build a list of all the functions that I would have to change? Maybe I can take a look at it ;)
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 07:21:26 pm
Sure, let's see ... I don't think it'll be that many but I'll take a look now!  Thanks!
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 07:44:00 pm
Here - just copy and pasted from the header files, hope this is OK:

CSFML_API sfWindow* sfWindow_Create(sfVideoMode Mode, const char* Title, unsigned long Style, sfWindowSettings Params);
CSFML_API sfWindow* sfWindow_CreateFromHandle(sfWindowHandle Handle, sfWindowSettings Params);
CSFML_API sfWindowSettings sfWindow_GetSettings(sfWindow* Window)
CSFML_API sfVideoMode sfVideoMode_GetMode(size_t Index);
CSFML_API sfVideoMode sfVideoMode_GetDesktopMode();
CSFML_API void sfView_SetFromRect(sfView* View, sfFloatRect ViewRect);
CSFML_API sfView* sfView_CreateFromRect(sfFloatRect Rect);
CSFML_API void sfSprite_SetSubRect(sfSprite* Sprite, sfIntRect SubRect);
CSFML_API sfRenderWindow* sfRenderWindow_Create(sfVideoMode Mode, const char* Title, unsigned long Style, sfWindowSettings Params);
CSFML_API sfRenderWindow* sfRenderWindow_CreateFromHandle(sfWindowHandle Handle, sfWindowSettings Params);
CSFML_API sfWindowSettings sfRenderWindow_GetSettings(sfRenderWindow* RenderWindow);

I already modified a few of these, here's my code:

Code: [Select]


sfWindow* sfWindow_Create(sfVideoMode* Mode, const char* Title, unsigned long Style, sfWindowSettings* Params)
{
    // Convert video mode
    sf::VideoMode VideoMode(Mode->Width, Mode->Height, Mode->BitsPerPixel);

    // Create the window
    sfWindow* Window = new sfWindow;
    sf::WindowSettings Settings(Params->DepthBits, Params->StencilBits, Params->AntialiasingLevel);
    Window->This.Create(VideoMode, Title, Style, Settings);
    Window->Input.This = &Window->This.GetInput();

    return Window;
}


sfWindow* sfWindow_CreateFromHandle(sfWindowHandle Handle, sfWindowSettings* Params)
{
    sfWindow* Window = new sfWindow;
    sf::WindowSettings Settings(Params->DepthBits, Params->StencilBits, Params->AntialiasingLevel);
    Window->This.Create(Handle, Settings);
    Window->Input.This = &Window->This.GetInput();

    return Window;
}


Code: [Select]


sfVideoMode Ret;

////////////////////////////////////////////////////////////
/// Get a valid video mode
/// Index must be in range [0, GetModesCount()[
/// Modes are sorted from best to worst
////////////////////////////////////////////////////////////
sfVideoMode* sfVideoMode_GetMode(size_t Index)
{
    sf::VideoMode Mode = sf::VideoMode::GetMode(Index);    
    Ret.Width        = Mode.Width;
    Ret.Height       = Mode.Height;
    Ret.BitsPerPixel = Mode.BitsPerPixel;
    return &Ret;
}
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 08:52:19 pm
Ok thanks :)

Some of them would be better with pointers (like sfWindowSettings -- this way we can pass NULL to get the default behaviour).

I'm more concerned about return values though. Declaring a global variable for each function that returns something is... ugly (and not multithread-friendly). Moreover you get a pointer to something internal, you don't know if you can modify it, or if it may be modified later by SFML, etc. Not clean at all.
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 09:03:49 pm
Yeah, agreed ...

Something I like to use often in this scenario, when I want to pass back something that I want to be unique and modifiable, but not have to be responsible for freeing it myself, is circular buffers.  An array of 8 or 16 of whatever object and an index that is used to get the next object, and moves circularly through the array based on its length, is more or less acceptable.  In C it might be a little awkward ... Forth makes it easy to add as a language feature. X)

Only way Forth can really use objects passed back is to have an address to something *not* on the stack, otherwise it will basically get clobbered almost immediately.  Maybe a workaround, like a small wrapper DLL...
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 09:47:28 pm
Quote
Maybe a workaround, like a small wrapper DLL...

Could be a solution, yes.
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 22, 2010, 10:07:35 pm
I guess, in places where it would be beneficial, you could make the parameter changes to CSFML ...

Anyway, aren't return-by-value structs still not so great, because, if you want the caller to return that struct, won't it go out of scope 2 levels up?

Be nice if those functions would just take an address to a struct to fill like I've seen in some other functions, and be done with it. :)
Title: Call and return by reference in CSFML
Post by: Laurent on December 22, 2010, 10:18:30 pm
Quote
Anyway, aren't return-by-value structs still not so great, because, if you want the caller to return that struct, won't it go out of scope 2 levels up?

Sorry, I don't understand what you mean. Return by value is the best option: since you never "point" to something that exists somewhere else, you can never go out of scope. You are the owner of what you get after calling the function.

Quote
Be nice if those functions would just take an address to a struct to fill like I've seen in some other functions, and be done with it.

It's a huge source of errors, and it's more verbose in my opinion.
I often see people doing this kind of error:
Code: [Select]
sfWindowSettings* settings;
sfWindow_GetSettings(window, settings); // crash
Title: Call and return by reference in CSFML
Post by: rogerlevy on December 23, 2010, 05:50:56 pm
On second thought, I realized that was completely wrong-sauce, you're right.  Sorry.  The structs get copied around so you don't lose anything I believe.

On the second point ... yeahhh ... seem to remember making similar mistakes.  Is there a better alternative?
Title: Call and return by reference in CSFML
Post by: Laurent on December 23, 2010, 09:28:56 pm
Quote
On the second point ... yeahhh ... seem to remember making similar mistakes. Is there a better alternative?

I don't think so.
Title: Re: Call and return by reference in CSFML
Post by: Flash on May 31, 2014, 07:31:37 pm
I know this is an old topic, but may I add my support to this request?
Forth is not the only language that is designed this way, it is true for Common Lisp (and other languages) as well.
The functions that get or return structs on stack would not need to be replaced, it would be OK to merely implement an alternative and make it clear in the documentation that they are only to be used for bindings.

I can do the additions myself, all I'd ask is that *if* I ever finish the Common Lisp binding, I'd be allowed to commit the changes back to CSFML, so that the binding would compatible with the main branch, without needing an additional wrapper dll.
Title: Re: Call and return by reference in CSFML
Post by: zsbzsb on June 01, 2014, 02:23:53 pm
And this would break almost every single existing binding for SFML, not to mention introduce more issues for binding maintainers.
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 01, 2014, 07:57:45 pm
How would alternative implementations that do not change any of the functions that already exist break anything?
Title: Re: Call and return by reference in CSFML
Post by: Laurent on June 01, 2014, 10:33:52 pm
If it's an alternative implementation, why does it have to be in CSFML? Can't you fork it and do the modifications in your own modified CSFML?
Title: AW: Call and return by reference in CSFML
Post by: eXpl0it3r on June 01, 2014, 10:52:50 pm
I guess it might be helpful to provide a bit more information on your idea, especially since the bumped thread is like four years old. ;)
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 01, 2014, 11:18:27 pm
If it's an alternative implementation, why does it have to be in CSFML? Can't you fork it and do the modifications in your own modified CSFML?
Well, of course I can do that. But what would it be good for? It would only add confusion and unnecessary work of re-merging if SFML or CSFML is updated. CSFML is being provided precompiled for many systems, and people would just need to download the binding + CSFML.
It would also enable other people with similar problems to write a binding directly to CSFML. There's a reason SDL only passes pointers.

Again, as I don't want to cause any work, I'd fork it anyway, and only ask to submit if the binding gets finished. It possibly was a bit premature to ask, as that is still a way off.  ;)

I guess it might be helpful to provide a bit more information on your idea, especially since the bumped thread is like four years old. ;)
The basic idea is to just provide alternative functions that pass pointers, e.g.

CSFML_GRAPHICS_API sfRenderWindow *     sfRenderWindow_create (sfVideoMode mode, const char *title, sfUint32 style, const sfContextSettings *settings)
=>
CSFML_GRAPHICS_API sfRenderWindow *     sfRenderWindow_create (sfVideoMode *mode, const char *title, sfUint32 style, const sfContextSettings *settings)
and
CSFML_GRAPHICS_API sfContextSettings    sfRenderWindow_getSettings (const sfRenderWindow *renderWindow)
=>
CSFML_GRAPHICS_API void sfRenderWindow_getSettings (const sfRenderWindow *renderWindow, sfContextSettings *settings)
I'm not so sure about the second example, or if it's better to create a new sfContextSettings struct and return it, but I'd rather have a "who creates it, is responsible" approach.

If anyone is interested, I asked a question on the Common Lisp side of this on StackOverflow (http://stackoverflow.com/questions/23579340/passing-and-returning-structs-to-c-functions-on-stack-from-common-lisp-with-cffi) a while back, to make sure I'm not missing anything.
Title: Re: Call and return by reference in CSFML
Post by: Jebbs on June 02, 2014, 12:53:33 am
I don't know if this helps you out at all, but you could look at DSFML-C (https://github.com/Jebbs/DSFML-C), which is a modified version of CSFML that removed all POD structs (sfVector2f, sfTime, etc) in lieu of using a set of scalars instead.

For example:
CSFML_GRAPHICS_API sfImage* sfImage_createFromColor(unsigned int width, unsigned int height, sfColor color);
Looks like
DSFML_GRAPHICS_API sfImage* sfImage_createFromColor(DUint width, DUint height, DUbyte r, DUbyte b, DUbyte g, DUbyte a);

(though now I realize this function passes the color in rbga order instead of rgba order :P)

Feel free to use it if you want, but some of it (the audio stuff) is a little experimental. Just a heads up.
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 02, 2014, 07:25:11 am
I don't know if this helps you out at all, but you could look at DSFML-C (https://github.com/Jebbs/DSFML-C), which is a modified version of CSFML that removed all POD structs (sfVector2f, sfTime, etc) in lieu of using a set of scalars instead.

For example:
CSFML_GRAPHICS_API sfImage* sfImage_createFromColor(unsigned int width, unsigned int height, sfColor color);
Looks like
DSFML_GRAPHICS_API sfImage* sfImage_createFromColor(DUint width, DUint height, DUbyte r, DUbyte b, DUbyte g, DUbyte a);

(though now I realize this function passes the color in rbga order instead of rgba order :P)

Feel free to use it if you want, but some of it (the audio stuff) is a little experimental. Just a heads up.
Thanks, this one would actually work.  :D
Deconstructing all structs seems a little overkill for my purposes, though, as I only have problems with very few functions, and you lose some readability. Still, it'd be a better alternative than having to maintain yet another fork, IMO.
Title: Re: Call and return by reference in CSFML
Post by: Laurent on June 02, 2014, 07:43:22 am
Quote
It would only add confusion
Having two versions of each function in CSFML would be confusing. Having a fork which is dedicated to this modification would be a lot clearer in my opinion.

Quote
unnecessary work of re-merging if SFML or CSFML is updated
Updating these functions every time CSFML is updated is not unnecessary work, it has to be done anyway. Of course it's easier for you if it's me who does it... ;)

Quote
CSFML is being provided precompiled for many systems, and people would just need to download the binding + CSFML
You can provide your own releases. And since people interested in this fork would be bindings creators, I don't think they would be afraid to compile it if they can't find a precompiled version for their platform.

Quote
There's a reason SDL only passes pointers.
Did they say it is for this particular reason?
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 02, 2014, 07:56:02 pm
Quote
It would only add confusion
Having two versions of each function in CSFML would be confusing. Having a fork which is dedicated to this modification would be a lot clearer in my opinion.

Quote
unnecessary work of re-merging if SFML or CSFML is updated
Updating these functions every time CSFML is updated is not unnecessary work, it has to be done anyway. Of course it's easier for you if it's me who does it... ;)
I'm sorry, I just realized that I made this request under false preconceptions.
For whatever reasons I thought that rogerlevy's list posted in this thread was accurate, and I still think that it would have been a good idea for ~10 functions (and little extra work to maintain).
However, knowing the CSFML source I should have known better, as this list contains none of the functions that return vectors, rects and similar stuff (I think I realized this a few weeks ago, but had forgotten, as I did not work on the binding in the meantime).
Thus I realize that having alternatives for that many functions might be confusing, and is additional work to maintain.


Quote
Quote
CSFML is being provided precompiled for many systems, and people would just need to download the binding + CSFML
You can provide your own releases. And since people interested in this fork would be bindings creators, I don't think they would be afraid to compile it if they can't find a precompiled version for their platform.
Well, I hope that the people interested in this fork would be Common Lisp Users. ;) And it would have been nice to just download the appropriate dll, load the bindings via quicklisp and everything would work, regardless of system. Alas, that's not gonna be. :P

Quote
Quote
There's a reason SDL only passes pointers.
Did they say it is for this particular reason?
No, it was an assumption on my part, because I couldn't think of a better reason other than speed (but they do it even for all structs). It might be one of several reasons, or not play a role.

So I'll see what I'll do. Possibly DSFML-C is the best alternative, as I really want to avoid having yet another fork unless I really have to. As I plan to have high-level lispy abstractions modeled on SFML anyway, the deconstructed parameters would be hidden anyway.
Title: Re: Call and return by reference in CSFML
Post by: Jebbs on June 02, 2014, 08:32:24 pm
Please be aware that DSFML-C is written specifically to interface with the D binding so it might not fit right for lisp in all cases.
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 02, 2014, 09:13:26 pm
Please be aware that DSFML-C is written specifically to interface with the D binding so it might not fit right for lisp in all cases.
How does this specificity manifest itself?
I thought it was just a normal C binding without structs.
Title: Re: Call and return by reference in CSFML
Post by: Jebbs on June 03, 2014, 12:35:51 am
In some cases, D is able to interface directly with C++, so I do that when I can and it makes sense. That means that some functions in DSFML-C expect C++ objects to be passed to them by address since those can be created in the D code.
Title: Re: Call and return by reference in CSFML
Post by: Flash on June 03, 2014, 07:26:37 am
In some cases, D is able to interface directly with C++, so I do that when I can and it makes sense. That means that some functions in DSFML-C expect C++ objects to be passed to them by address since those can be created in the D code.
OK, so I can't use it either.   :-\
Title: Re: Call and return by reference in CSFML
Post by: Jebbs on June 03, 2014, 07:51:43 am
It is only in some cases.

If you don't care about using sf::InputStream's or creating your own sf::SoundStream everything should work fine.