SDL 2.0: Evaluating API Usability (Long)

Hello,

I’m a 3rd year Software Engineering undergraduate at University of
Southampton (http://ecs.soton.ac.uk). I also have a part-time
development job with Sony.

As part of my degree, I have to undertake a research project. I have
decided to look at API usability, using SDL as an example.

Background==========

An API is essentially programmer-centric (whereas an ABI is
implementation-centric). There is a lot of literature stating that ‘Good
API design is important’, but very little empirical research as to what
constitutes good design.

For example, from the C Std Library, opening a file is done via:

FILE *fopen(const char *, const char*);

with FILE * returning NULL on error. However, it could just as easily be
written as:

int fopen(const char*, const char*, FILE *);

With the error code being returned. Alternatively,

void fopen(const char*, const char*, FILE *);

with any error being placed into a global variable.

Does one of these offer any particular advantage over the others? Does
it depend on what kind of application you’re developing etc, etc?

Objective

I am interested in researching what makes a good API, from a
programmer’s perspective. I also intend to examine the links between C
and C++ APIs, specifically, is it possible to design a C API in a way
that makes a native C++ API more intuitive or straight-forward.

Hopefully, it will be possible for my results to be fed-back into the
development of SDL 2.0, to make it even easier to use.

Next Step

Following my initial research into the area, I have come here to ask
users of SDL for their views and experiences using SDL.

I am NOT interested in the capabilities of SDL - this is a question for
Sam and Ryan, who, as professional game developers, are in a MUCH better
position to judge what is and is not necessary.

The question I have is what YOU like or don’t like about the way APIs
within SDL are presented. What are your pet hates? What makes you go
’wow, that’s really easy to use’?

If you would like to participate, please read the ‘Legal Bit’ at the end
then answer the following questions (remembering to reply to me or CC me):


START

First, in order to classify my results, please categorise both your
education AND experience.


CLASSIFICATION

EDUCATION - One of:

- SELF-TAUGHT (No formal programming teaching / qualifications)
- NON-DEGREE programming course (E.g. Sun Java Cert or people who had

a small amount of programming as part of a degree, such as Maths,
Physics or Electronic Engineering)
- DEGREE: More than 1 year of a Computer Science or related (Electronic
Engineers who were TAUGHT a lot of programming as part of their degree
fit this category).

EXPERIENCE - One of:
- FOR FUN: Amateur/just for fun devs.
- PART-PROFESSIONAL - professional devs with less than 2 years
full-time experience in a commercial environment. (either inside or
outside games industry).
- FULL-PROFESSIONAL full-time non-game developer with 2 or more years
experience. (Includes people who have not worked in games for 2 or more
years)
- GAME DEV professional (full-time) game developer with 2 or more years
experience.

For example, I would be DEGREE, PART-PROFESSIONAL.


QUESTIONS

These questions are fairly free-form. Please feel free to be as verbose
as you like, quoting examples, C, C++ or other code (even Lisp or
Prolog!) if you feel it is appropriate.

  1. What do you like about the presentation of the SDL APIs? Which tasks
    do you find particularly easy, straightforward or simple? Which APIs do
    you feel work really well for the task they are intended for?

  2. What DON’T you like about the presentation of the SDL APIs? Which
    task do you find particularly difficult, awkward or confusing? Which
    APIs do you feel make the task more difficult? What are your pet hates?

  3. How do you find error handling? What do you like about it? What don’t
    you like about it? Are there particular examples of error handling in
    other APIs that you prefer? Why?

  4. If you use / have used SDL with C++, please answer the following:
    a. Do you wrap SDL in C++ class(es)?
    - If not, why not?
    - If so, what difficulties / gotchas have you encountered? Which APIs
    have been particularly troublesome?
    b. Have you tried using exceptions in your SDL code? Which approach(es)
    have you used? Did you give-up and go back to traditional (C-style)
    error handling and if so, why?

  5. Any other comments that do not fit the above.


END

Legal Bit (Actually REALLY IMPORTANT!)

It is my intention to use any comments made in relation to this post as
part of my research, for which, the copyright will be held by myself
and/or University of Southampton (UK).

Data Protection Act 1998. Any personal data collected will be used
exclusively in connection with this research project. The originating
email address will be stored purely in order to facilitate the collation
of the comments made by an individual (e.g. to remove duplicates) and
for direct email communication by me in order to clarify any comments.
The final published data will not contain any information that can be
used to identify individual contributors.

For the avoidance of doubt, please email your response to me directly
(CC: will be fine). I will take this as your acknowledgement and
confirmation of consent. NOTE: If you fail to do this, I will NOT be
able to use your contribution!

Many, many thanks in advance,

Eddy

Edward Cullen
February 2008

Hi.

If I have left anything out, feel free to let me know. I apologise in
advance if I rambled a bit, or went slightly off topic.


CLASSIFICATION

DEGREE

PART-PROFESSIONAL


QUESTIONS

  1. What do you like about the presentation of the SDL APIs? Which tasks
    do you find particularly easy, straightforward or simple? Which APIs do
    you feel work really well for the task they are intended for?

SDL is simple. It is easy enought that I can remember most of the API
calls and arguments from memory. The functions are simple enough that
most of the time one doesn’t need to look beyond the function
prototype itself for documentation. I think its wide user base attests
to how much it gets right in its API.

  1. What DON’T you like about the presentation of the SDL APIs? Which
    task do you find particularly difficult, awkward or confusing? Which
    APIs do you feel make the task more difficult? What are your pet hates?

Const correctness, or lack thereof, is annoying. C++ code is more
prone to using const a lot (because member functions can be marked
const) which occasionally means one must make unsightly const_casts to
overcome the API. The functions (I can’t remember the specific ones)
logically shouldn’t be const. In addition, there are some functions
(SDL_BlitSurface) that would appear to be const-incorrect, but in fact
need non-const pointers. Conceptually, blitting between two surfaces
would leave the source unchanged, yet the source is non const (I
remember going through the SDL source at one stage to figure out if
there was a reason, if memory serves there was one). Then again, the
source rectangle is not modified, but is not marked const.

SDL_ListModes is evil. I dislike casting a pointer to -1 to check for
a condition. An additional API call would be preferred:
if( !SDL_AnyVideoMode() )
{
// use SDL_ListModes()
}

I’m not sure if they’ve fixed this, but when you call SDL_SetVideoMode
more than once (on Windows at least), and you have an OpenGL context
on it, the opengl context is lost (along with textures, shaders etc
you have stored in the context). This is annoying, because AFAIK it is
possible under Windows to resize a window without destroying the
context. Another annoyance is (again, under Windows at least) if you
hold on the window title bar, your program’s main thread seems to
freeze. I don’t know if this is caused by how Windows handles it.

The lack of window APIs to discover the screens current resolution and
or position the SDL window (environment variables are a poor API
choice, IMHO). I know SDL 1.3/2.0 is supposed to address this.

void SDL_ToggleFullscreen() seems rather pointless given that it
doesn’t work reliably in a cross platform manner. A better alternative
is one like:
SDL_Surface *SDL_ToggleFullscreen(), so it could be implemented under
all platforms.

More consistency in event enums to event types. For example,
SDL_ResizeEvent uses the enum SDL_VIDEORESIZE and SDL_ExposeEvent uses
SDL_VIDEOEXPOSE. I never can remember whether to check if(event.type
== SDL_EXPOSEEVENT) or to cast SDL_VideoExpose &expose = event.expose.

SDL has an implementation of a thread safe queue, it would be
fantastic if it exposed that as a type for people to use for
inter-thread-communication. At the moment, you can have number of
source threads pushing events towards one event sink, but some of my
programs require bi-directional inter-thread messages, and a queue is
one of te simplest and easiest ways to do this.

SDL_UserEvents are great, but it is difficult for an extension library
writer (example: Bob Pendleton’s NET2 library) to ensure that a given
event.user.code isn’t being used by the library user, or by another
extension library. SDL should expose a way to allocate event.user.code
values (or ranges), and deallocate them:

int base_user_code = 0;

Net2_Init()
{
base_user_code = SDL_AllocUserEventRange(10); // 10 distinct user
code types
}

Net2_Quit()
{
SDL_FreeUserEventRange(base_user_code);
}

Alternatively, SDL could only allow a single user event code type per
library, and leave it up to the library writer to provide an
additional enumeration in their event.user.data1 or data2 structure
pointers. Still, there should be some way to reserve certain code
values in advance to ensure that at run time each event code maps to a
unique event type.

  1. How do you find error handling? What do you like about it? What don’t
    you like about it? Are there particular examples of error handling in
    other APIs that you prefer? Why?

The error handling is, for most uses, simple and easy. By having a
consistent usage, functions returning pointers return NULL on failure,
all other functions return negative numbers on failure. This leaves
scope for functions returning non boolean errors (example:
SDL_BlitSurface() returning -2 signals a special, recoverable
failure). It also means that to catch all errors on a SDL function
Foo, one writes if( SDL_Foo() < 0 ) { /* handling */ }, which is easy
to remember. Looking up the source, it appears to be thread safe, an
extra bounus. It would be nice to have more symbolic error constants
though, AFAIK there is no #define for the -2 value returned from
SDL_BlitSurface.

  1. If you use / have used SDL with C++, please answer the following:
    a. Do you wrap SDL in C++ class(es)?
    - If not, why not?
    - If so, what difficulties / gotchas have you
    encountered? Which APIs

have been particularly troublesome?

a) Yes, mostly. It was quite easy to write RAII wrappers around the
majority of SDL (well, any function pair that allocates and
deallocates memory, not much point wrapping the others). Trouble was
caused by the threading API, as detailed below.

  b. Have you tried using exceptions in your SDL code? Which approach(es)

have you used? Did you give-up and go back to traditional (C-style)
error handling and if so, why?

b) Yes. I’m not sure what you mean by “approach” here, I just made it
so that the RAII wrapper constructor for a given class would either
allocate successfully, or throw an exception (usually
std::runtime_error unless I wanted to handle that error differently,
i.e. file not found) which usually just contained the SDL_GetError()
string.

However, I am currently having trouble with the threading API. I am
writing a multi-threaded network program, and most network errors (in
this program, I do not attempt recovery in the event of network
failure) propagate to the thread function (the one that gets passed to
SDL_CreateThread). This function has a try…catch block in it,
catching std::exception instances and also a general catch statement
(catch(…)). However, when ever an exception is thrown the program
crashes hard with an access violation. Debugging this is difficult (I
suspect the error is caused during stack unwinding). Because I am
paranoid about wrapping pointers in smart pointers or RAII wrappers of
different kinds, I don’t think that this error is caused by my code,
then again I have found SDL to be quite stable, so I am still 50/50
whether it is SDL or me that is causing this problem. I am tempted to
try convert my program to traditional C error handling, to see if the
problem persists, but that is a lot of work. I am loath to blame SDL
because in my experience I am always to blame, but I am quite
experienced with C++ and I have yet to find anything wrong that I have
done that could have caused this.

  1. Any other comments that do not fit the above.

SDL is fantastic :)>> --------------

END

Legal Bit (Actually REALLY IMPORTANT!)

It is my intention to use any comments made in relation to this post as
part of my research, for which, the copyright will be held by myself
and/or University of Southampton (UK).

Data Protection Act 1998. Any personal data collected will be used
exclusively in connection with this research project. The originating
email address will be stored purely in order to facilitate the collation
of the comments made by an individual (e.g. to remove duplicates) and
for direct email communication by me in order to clarify any comments.
The final published data will not contain any information that can be
used to identify individual contributors.

For the avoidance of doubt, please email your response to me directly
(CC: will be fine). I will take this as your acknowledgement and
confirmation of consent. NOTE: If you fail to do this, I will NOT be
able to use your contribution!

— Brian <brian.ripoff at gmail.com> wrote:

I’m not sure if they’ve fixed this, but when you call
SDL_SetVideoMode
more than once (on Windows at least), and you have an OpenGL context
on it, the opengl context is lost (along with textures, shaders etc
you have stored in the context). This is annoying, because AFAIK it
is

void SDL_ToggleFullscreen() seems rather pointless given that it
doesn’t work reliably in a cross platform manner. A better
alternative
is one like:
SDL_Surface *SDL_ToggleFullscreen(), so it could be implemented under
all platforms.

I’m pretty sure these are both being dealt with for 1.3 (the context
loss in Windows definitely, SDL_ToggleFullScreen is deprecated as known
to only work in X).

Otherwise, I really haven’t plumbed the depths of SDL enough to make
any serious judgement on its worth as an API.____________________________________________________________________________________
Looking for last minute shopping deals?
Find them fast with Yahoo! Search. http://tools.search.yahoo.com/newsearch/category.php?category=shopping

I’m not sure if they’ve fixed this, but when you call SDL_SetVideoMode
more than once (on Windows at least), and you have an OpenGL context
on it, the opengl context is lost (along with textures, shaders etc
you have stored in the context). This is annoying, because AFAIK it is
possible under Windows to resize a window without destroying the
context.

(Not to hijack the thread, but…)

Here’s a patch to fix that. It’s not an API issue. If people could play
with that and let me know if it causes any problems, I’ll commit it to
Subversion.

–ryan.

-------------- next part --------------
An embedded and charset-unspecified text was scrubbed…
Name: SDL-wingl-no-rebuild-context-on-resize.diff
URL: http://lists.libsdl.org/pipermail/sdl-libsdl.org/attachments/20080311/ed66a4dc/attachment.asc

Since I’m an SDL user as much as an SDL developer, I figured I’d fill
this out.


CLASSIFICATION

EDUCATION - One of:

  • SELF-TAUGHT (No formal programming teaching / qualifications)

(I have an undergraduate degree, but it’s not in Computer Sciences.)

EXPERIENCE - One of:

  • GAME DEV professional (full-time) game developer with 2 or more years
    experience.
  1. What do you like about the presentation of the SDL APIs? Which tasks
    do you find particularly easy, straightforward or simple? Which APIs do
    you feel work really well for the task they are intended for?

SDL_SetVideoMode() is the best thing, ever. I don’t understand why every
other platform takes dozens of lines of code to accomplish the same thing.

Good design either keeps the API dirt simple, or provides the “dirt
simple” API layered over the more low-level one, for times when
dirt-simple would be too limiting for legitimate cases…otherwise, you
end up with the same boilerplate cut-and-paste in every application to
build a DirectX window, or a GL context, etc.

I like that the API worked very well as an abstraction layer…SDL has
shown up in some pretty exotic locations and retained source compatibility.

I think the philosophy of add-on libraries worked out, since it lets us
throw away pieces that didn’t work so well (SDL_mixer, SDL_net,
SDL_image, etc, could all just be superceded by a totally different
library…those that want the old stuff can still use it, since it
doesn’t break the SDL API abstractions to get the job done…also, it
removes the bloat from the base library…I think SDL_rtf is awesome,
but I’m happy it’s not part of SDL itself. Basically, it gives us
evolutionary wiggle room.

  1. What DON’T you like about the presentation of the SDL APIs? Which
    task do you find particularly difficult, awkward or confusing? Which
    APIs do you feel make the task more difficult? What are your pet hates?

I think most of them are resolved for 1.3.

Probably the biggest killer in 1.2, from an API stance, was that the API
dictates that we have to keep internal state for a single window…which
led to an implementation with the same attitude…so we couldn’t just
add multiwindow support to the library. Not only would we need a whole
new set of public functions, but we’d have to flush out a lot of
internal code assumptions inside SDL.

The best parallel I could give is if the ANSI C functions had these
signatures:

 int fopen(const char *fname, const char *mode);  // 0 on success!
 void fclose(void);

…what, you access more than one file at a time? :slight_smile:

I think there are a few things that are past their lifespan in the API:
CD audio, for example.

  1. How do you find error handling? What do you like about it? What don’t
    you like about it? Are there particular examples of error handling in
    other APIs that you prefer? Why?

I can’t ever find an error handling API that I like…my mind changes
from day to day, but SDL seems to be least irritating in most cases:

  • easy to get information in a single return value
  • call a function to get a human-readable string.

The “human readable string” part is where it breaks down for
me…someone has to deal with managing that memory (would you be happy
if sin(NaN) called malloc())?, what do you do about localizing that
string? What about character encodings? How do you show this error to
the user when you don’t know what might come out of the library (be it
geek-speak or a curse word)?

As a resident of the en_US locale that likes to read debug output, it
works for me, but I think that the C runtime “errno” concept works
better (not the global variable. I mean having a giant enum of all
possible errors)…then again, lots of meaning gets overloaded on some
of those errno values, and there are a LOT of subtle ways SDL can fail.

Like I said, I haven’t found anything I like anywhere.

  1. If you use / have used SDL with C++, please answer the following:
    a. Do you wrap SDL in C++ class(es)?
    • If not, why not?
    • If so, what difficulties / gotchas have you encountered? Which APIs
      have been particularly troublesome?

I have called it from C++ classes that implement an abstraction:

// one of these for each targeted platform.
class SDLVideo : public Video
{
     create_window();
     blit();
     get_mouse_xy();
};  // or whatever.

But I haven’t ever tried to do a real formal C+±ification of SDL.
Frankly, I find that sort of thing to be a complete waste of time. It
adds complexity for no obvious payout.

b. Have you tried using exceptions in your SDL code? Which approach(es)
have you used? Did you give-up and go back to traditional (C-style)
error handling and if so, why?

C++ error handling only makes life harder, in my experience. I avoid it
whenever possible. It makes it harder to walk through programs, it risks
memory leaks…it’s a structured GOTO, basically.

Despite working with it all day (maybe BECAUSE of working with it all
day) I’m somewhat anti-C++. I probably skew the results. :slight_smile:

–ryan.

Hi Paul,

Please don’t feel you “don’t know enough about SDL” to make comment; I
need a cross-section of views to make my results valid - if all I get is
responses from pro game devs, then it’s gonna skew my results, isn’t it?

Feel free to respond to me privately if you feel intimidated :slight_smile:

Eddy

Paul Duffy wrote:> — Brian <brian.ripoff at gmail.com> wrote:

I’m not sure if they’ve fixed this, but when you call
SDL_SetVideoMode
more than once (on Windows at least), and you have an OpenGL context
on it, the opengl context is lost (along with textures, shaders etc
you have stored in the context). This is annoying, because AFAIK it
is

void SDL_ToggleFullscreen() seems rather pointless given that it
doesn’t work reliably in a cross platform manner. A better
alternative
is one like:
SDL_Surface *SDL_ToggleFullscreen(), so it could be implemented under
all platforms.

I’m pretty sure these are both being dealt with for 1.3 (the context
loss in Windows definitely, SDL_ToggleFullScreen is deprecated as known
to only work in X).

Otherwise, I really haven’t plumbed the depths of SDL enough to make
any serious judgement on its worth as an API.

  ____________________________________________________________________________________

Looking for last minute shopping deals?
Find them fast with Yahoo! Search. http://tools.search.yahoo.com/newsearch/category.php?category=shopping


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

I’m posting this to the ML since I think the results of those mails can be
useful for the API finalization of the new SDL.

CLASSIFICATION

DEGREE

EXPERIENCE

GAME-DEV

  1. What do you like about the presentation of the SDL APIs? Which tasks

do you find particularly easy, straightforward or simple? Which APIs do
you feel work really well for the task they are intended for?

I found the initialization stage and event handling of SDL to be perfect.
They are SIMPLE and powerful and the assumption they made can be scaled
quite well in a wide range of contexts, from the embedded system to the
desktop.

  1. What DON’T you like about the presentation of the SDL APIs? Which

task do you find particularly difficult, awkward or confusing? Which
APIs do you feel make the task more difficult? What are your pet hates?

  • I think the way SDL handles the audio part is not as good as the other
    areas. I know it’s very low level and should be wrapped by something of
    higher level like SDL_Mixer, but I always end with using other frameworks
    for audio (openal for instance).

I think it will need a simple, crossplatform, way to expose at least the
number of hardware output channels available (5+1, 7+1…) and a sound
capture api. AFAIK we’ll get both in 1.3/2.0.

  • I also dislike the enviroment variable approach for a lot of useful
    things, I’m talking about:
  • window positioning
  • window id for embedding SDL ( SDL_UseWindow(void *) ? this will give also
    the option to embed SDL when the window was already open usewindow will
    detect this and close the actual window and calling again SetVideoMode on
    the new surface).
  • audio/video driver selection
  • I don’t like how video overlays are handled on OSX and Win32, there is for
    sure room for improvements, but, at least for win32, this will require at
    least a partial return to directx).
  1. How do you find error handling? What do you like about it? What don’t

you like about it? Are there particular examples of error handling in
other APIs that you prefer? Why?

I like SDL error handling. I’ve worked with a lot of frameworks that use
exception for error handling at it’s a mess. You write more code, and you’ll
end out with debug nightmares since exception may be filtered,
misinterpreted, not catched for a lot of different reasons (C code between
two C++ modules, minor differences in libgcc/libstdc++, universal binaries
on OSX 10.3…)

  1. If you use / have used SDL with C++, please answer the following:
    a. Do you wrap SDL in C++ class(es)?

Only in a pair of small projects I wrote mostly for experiment.

            - If not, why not?

Usually the SDL calls are wrapped in higher level, not generic, objects,
there is no point to have a class SDLSurface if you have an higher level
surface object that handles for instance also resource handling, special
effects and blit operations specifical for that particular engine.

            - If so, what difficulties / gotchas have you encountered?

Which APIs
have been particularly troublesome?

I had a lot of problem with 16bit surfaces and endiannes on a 2d game I
ported from win32 to mac a few years ago (www.robinhood-game.com).

    b. Have you tried using exceptions in your SDL code? Which

approach(es)
have you used? Did you give-up and go back to traditional (C-style)
error handling and if so, why?

Answered a few questions above, exceptions are evil. Besides that using them
for “normal” error conditions cause also a big performance hit:

for (x = 0; x < 1000000; ++x)
if (!is_odd(x))
even++;

Is faster by a factor 10 than:

for (x = 0; x < 1000000; ++x)
try { is_odd(x)); }
catch (…) even++;

This is a stupid example but I’ve seen frameworks using exceptions to report
missing intersections or similar, very common, situations…

  1. Any other comments that do not fit the above.>


Bye,
Gabry

Window centering (without environment vars) would be great.

Window centering (without environment vars) would be great.

It’s already in there. :slight_smile:

-Sam Lantinga, Lead Software Engineer, Blizzard Entertainment

Cool, is there any command reference for this new SDL yet? :slight_smile:

Here’s a patch to fix that. It’s not an API issue. If people could play
with that and let me know if it causes any problems, I’ll commit it to
Subversion.

(This is svn revision #3572 now, so you shouldn’t lose your GL context
on resize any more with the windib driver.)

–ryan.

Very nice! Gives me a good excuse to figure out how to build SDL on
windows (and I might finally get around to messing with 1.3 then :)On Wed, Mar 12, 2008 at 10:02 PM, Ryan C. Gordon wrote:

Here’s a patch to fix that. It’s not an API issue. If people could play
with that and let me know if it causes any problems, I’ll commit it to
Subversion.

(This is svn revision #3572 now, so you shouldn’t lose your GL context
on resize any more with the windib driver.)

–ryan.