Status-encoding (Re: SDL 1.3 proposed conventions)

From experiences, just a few points of critisism over hresult:
a) one-bit warn/error classicifation is enough for most cases
but not fine-grained enough in some result-codes. For the
reasons of using a bit more “severeness”-codes, I like to
point to a push-model for (compressed-)sound playback that
could answer like

  • sound-sample missed, user did not notice, oversampled
  • sound-packet not decoded, re-sync with next frame ok
  • hardwary-driver says busy, try again with next packet
  • hardware-driver went away, panicking.
    I’ve seen quite some systems with more errorcode-spreading
    wrt to severness, like 8 or 16 subclasses, but the more
    subclasses one adds, the less the common user will write
    glue-code to handle them all appropriately. Two subclasses
    are almost always handled, that’s for sure.
    b) defining lib-codes does somehow require a central mapping
    of those ints to the libs - if not predefined by the
    main package-holder. A dynamic extension system, oh my g…
    lots of managment for a thing that usually not tested
    in the glue-code, mostly for error-reporting and for use
    with an xp-holder application that just binds some modules
    and which is only there to manage the rest. I remember
    another model that did always return a static-string as
    the (sdl_)status code, and all category-matching (like
    severeness and subsystem) was done by string-substr and
    -strstr operations. Actually, if you have an module-defined
    error-code and a managment-system that can register some
    strerror-routines from those modules then the subsystem
    can be deduced from the staticstring returned by strerror.

Also, one does not likely see the ipv4 problem - some
subsystems just need 4 statuscodes, others need 400, and
just making the “C”-field big enough will make you said
as soon as the “L”-field is used up. Just theoretic you
say, hmmmm.

David MacCormack wrote:>

Here’s my 2 cents…

Here are some proposed conventions for the SDL 1.3 -> 2.0 rewrite:

API conventions:

SDL functions return a boolean value or a pointer value

I see where you’re going, and I like it. I’m not sure if you’re just
interested in feedback on your proposal or if you’re soliciting
submissions; if it’s the former than feel free to skip this :).

A different approach, that’s worked well (in practice) for me in the past
is to make every (or at least most) functions return a status, a long,
that represents various information about the function call. It can
contain any necessary information, that is accessable via macros; similar
to HRESULTS. Here’s an example off the top of my head.

    +-----------------------+

bit(s) + 31 | 30 - 16 | 15 - 0 |
±----------------------+
meaning + S | L | C |
±----------------------+

S = success/fail bit. Basically. This would represent whether or not
the error is a fatal one or not.

L = the interface/lib that the error belongs to (i.e. video, audio,
etc…). 15 bits makes for A LOT of possibilities, so you could
specify a range that’s SDL only, and leave the rest open for
application specific stuff (e.g. you could make bit 30 say
whether or not it’s SDL or APP specific, and make 29-17 the
interface id itself). And inside the SDL range you could specify
another range (via a few more bits) to separate generic errors
(e.g. Can’t create window) from implementation specific errors
(e.g. Can’t init DirectX). Also, you could have a few hardcoded
interfaces, like one called errno. That’d allow you to wrap
errno values inside one of these.

C = the code itself.

And then have macros to build 'em and break 'em apart.
Something like
typedef long SDL_RESULT;
#define SDL_STATUS_CREATE(s,l,c) /* exciting shift ops here /
#define SDL_STATUS_CREATEI(s,lib,imp,c)
/
crate an implementation specific code /
#define SDL_STATUS_SUCCEEDED(result) /
bit 31 = 0 ? /
#define SDL_STATUS_LIB(result) /
result & bits 30-16, or whatever /
#define SDL_STATUS_CODE(result) /
result & bits 15-0 /
/
define status values /
#define SDL_SUCCESS 0
#define SDL_FAIL 1
/
define interfaces/libraries /
#define SDL_LNULL 0 //anything generic that’s not handled by errno
#define SDL_LERRNO 1
#define SDL_LVIDEO 2
#define SDL_LAUDIO 3
etc…
/
define implementations /
#define SDL_INULL 0 //non implementation specific errors
#define SDL_IWIN32 1
#define SDL_IQUICKDRAW 2
etc…
/
define implementation independant codes /
#define SDL_CCREATWIN 1
etc…
/
define implementation dependant codes /
#define SDL_CINITDX 1
etc…
/
define some errors */
#define SDL_EOK SDL_CREATE(SDL_SUCCESS, SDL_LNULL, 0)
#define SDL_ENOMEM SDL_CREATE(SDL_FAIL, SDL_LERRNO, ENOMEM)
#define SDL_ECREATEWIN SDL_CREATE(SDL_FAIL, SDL_LVIDEO,
SDL_CCREATWIN)
.
.
.
SDL_RESULT SDL_Init(…) {
SDL_RESULT result = SDL_EOK;
if (malloc failed)
return SDL_ENOMEM;
if (could not create window)
return SDL_ECREATWIN;
if (could not init direct x under win32)
return SDL_STATUS_CREATEI(
SDL_FAIL, SDL_IVIDEO, SDL_IWIN32, SDL_CINITDX);
return result;
}

/*

  • Much like strerror from errno.h.
  • Note that before I said ‘most’ functions return a status value.
  • This is a good example where it doesn’t really make sense.
    /
    const char * SDL_StrError(SDL_RESULT result) {
    /
    bigass array lookup/case statement to evaluate result
    or return the empty string if there’s no error
    */
    }

That thing I like about this is that its really just errno on crack. It’s
simple, thread safe, and it should be able to evolve well. The thing I
hate about it is that because every function returns a status, you
can’t use any functions as parameters to other functions. One could
perhaps mix this with a scheme like errno, where you have a global
variable instead of returning a status value for everything, but then you
get into threading issues. I wound up just biting the bullet and living
with the fact that you can’t return “real” (e.g. pointers) from
functions, but your milage may vary.

SDL functions are prefixed with “SDL2_” … “SDL_” ?

The only reason I can see this as necessary is if you plan on allowing the
user to use both SDL 1.x and SDL 2.x in the same app (and thus link to
both libs and thus have to prevent linker collisions). Is that the idea?
Otherwise my question would be “why?”

SDL functions take a status pointer as the first argument
This status pointer can be 0, but no error information will be saved.

In the scenerio I described above, the first parameter whould instead be a
pointer to a structure to be modified, if the function was to do that.
Here’s an example based on the current api.

SDL_RESULT SDL_LoadBMP(SDL_Surface** surface, const char *file);
void SDL_FreeSurface(SDL_Surface *surface);

void myfunc() {
SDL_Surface* surface = NULL;
SDL_RESULT result;

result = SDL_LoadBMP(&surface, “myfile.bmp”);
if (SDL_SUCCEEDED(result)) {
SDL_FreeSurface(surface);
} else {
fprintf(stderr, “could not load myfile.bmp: %s\n”,
SDL_StrError(result));
}
}

Anyway, that’s it. Sorry this went on so long; I tried to be as brief as
possible :). There are of course a ton of varients on this theme, this
is just one of them.

Dave

David MacCormack
djm at maccormack.net

From experiences, just a few points of critisism over hresult:
a) one-bit warn/error classicifation is enough for most cases
but not fine-grained enough in some result-codes.

Again, what I suggested was just an example; in retrospect I probably
shouldn’t have given it as it just confused the point I was trying to
make: consider using bit encoded fields as return values. You say you’re
experience lends to wanting more status bits? Sure! There’s 32 to play
with :). Like I said, that was just off the top of my head.

b) defining lib-codes does somehow require a central mapping
of those ints to the libs

True, but so does Sam’s proposal (using an enum). Personally, I don’t
have a problem w/ that :). In fact, the only difference between what I’m
suggesting and what sam proposed is:

  1. Make the function return the status instead of passing a pointer to be
    set

  2. Make the values/order in the enumeration mean something, so that
    they can be picked apart w/ macros.

I should have just said that in the first place.

DaveOn Mon, 28 May 2001, Guido Draheim wrote:

David MacCormack
@David_MacCormack