PascalGameDevelopment / SDL2-for-Pascal

Unit files for building Free Pascal and Delphi applications using the SDL2 library
https://pascalgamedevelopment.github.io/SDL2-for-Pascal/
Mozilla Public License 2.0
99 stars 18 forks source link

Opaque structs and SDL_net #140

Open suve opened 3 months ago

suve commented 3 months ago

In most of SDL headers, opaque structs use the following kind of typedef:

typedef struct SDL_Thing SDL_Thing;

As such, when writing C code, the following variable declaration:

SDL_Thing thing;

Is resolved by the compiler into:

struct SDL_Thing thing;

Which causes a compilation failure, as struct SDL_Thing is an opaque struct with unknown size. Hence, to declare a pointer variable, the programmer must explicitly declare the variable as a pointer:

SDL_Thing *thing;

However, for whatever reason, SDL_net does things differently, and uses the following kind of typedef:

typedef struct _Thing *Thing;

As such, when writing C code, the following variable declaration:

Thing thing;

Is resolved by the compiler into:

struct _Thing *thing;

Which compiles fine, as this creates a pointer variable - unbeknown to the programmer (unless they actually look at the typedef).


So now, my question: how should we handle this in sdl2_net.pas in terms of type naming?

  1. Keep the API similar to other units: make the TThing unavailable, and only use PThing everywhere. This makes it clear that PThing is a pointer to some data the programmer isn't meant to touch.

  2. Keep the API close to the original C headers, and use TThing. This obscures the information that TThing is a pointer.

Free-Pascal-meets-SDL-Website commented 3 months ago

Which of these solutions do you prefer and why?

suve commented 3 months ago

I'd prefer to go with the first solution (no TThing, use PThing instead) because to me, receiving a "bare" value and a pointer to a value carry different connotations. With a "bare" value, I'd expect to be able to just copy it and voilà, now I have two independent instances of TSomeType. This is obviously not the case with pointers - if I copy a pointer, both the original and the copy point to the same object and manipulating one of them influences the other.

Of course, one can argue that there are plenty of APIs which return "handle" values, which are just ints (or some other primitive type) that identify a resource - like the UNIX open() API, for example. And well, yeah, if you use socket(2) you also get the socket as a file descriptor handle - so maybe SDL_net is kinda trying to emulate that?

Still, I think that my original point still stands - making it a pointer type should convey to the programmer that they're not dealing with pass-by-value mechanics.

Free-Pascal-meets-SDL-Website commented 3 months ago

I agree with your point. Usually we try to stay as close to the original code as possible. In this instance though it is potentially confusing. Not only for C programmers, but also for users of our bindings, as we just decided to go for typed pointers for opaque C structures.

We may add a SDL_net hint to this discussion in the cheat sheet opaque structures chapter.

Best regards