Re: [AD] 4.3 error handling |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
- To: Coordination of admins/developers of the game programming library Allegro <alleg-developers@xxxxxxxxxx>
- Subject: Re: [AD] 4.3 error handling
- From: Elias Pschernig <elias@xxxxxxxxxx>
- Date: Wed, 07 Jun 2006 23:32:51 +0200
On Mon, 2006-06-05 at 16:28 -0700, Chris wrote:
>
> Besides, with the way that code is, you can use any of the three at any time.
> Don't want to use the try/catch defines? Then just call
> al_error_disable_throws() once at the beginning of your program and don't
> think anything of them (just be sure to check for failure return codes). Too
> lazy to do your own error checking? Leave throws enabled and don't worry
> about the try and catch defines.
True. We could even additionally provide a callback (NULL by default),
but if you set one with al_set_error_callback, then it is gets called
(and no longjmp-exception is raised).
> There's many times I wish I could just execute a string of commands and not
> have to check the return code of each one individually. But I'd still like to
> be able to handle the errors manually myself, without having to use a
> seperate callback function. Something like:
>
> al_error_try {
> audio_driver = al_audio_init_driver(NULL);
>
> main_voice = al_voice_create(audio_driver, 44100, AL_AUDIO_16_BIT_INT,
> AL_AUDIO_4_CH, 0);
> al_voice_get_long(main_voice, AL_AUDIO_FREQUENCY, &voice_freq);
> al_voice_get_enum(main_voice, AL_AUDIO_CHANNELS, &channels);
>
> main_mixer = al_mixer_create(voice_freq, AL_AUDIO_32_BIT_FLOAT, channels);
>
> al_voice_attach_mixer(main_voice, main_mixer);
> }
> al_error_catch {
> AL_ERROR code = al_get_last_error();
> show_my_error("Error initializing sound!\n%s\n", al_get_error_string());
> if(no_sound_is_fatal)
> al_error_throw(code);
> }
Yeah, this example makes more sense. Still, it won't occur often - an
initialization as complicated as above only should be necessary if you
do something special. If you just want to use al_play_sample, then an
al_init_audio() should be all that's needed (and therefore a simple if
would be less code than the al_error_try {} al_error_catch {}).
Actually, I would like this:
al_init(AL_INIT_ALL)
with:
#define AL_INIT_ALL (AL_INIT_KEYBOARD | AL_INIT_TIMER | AL_INIT_MOUSE |
AL_INIT_SOUND)
Anyway, I better try to get back on topic..
>
> > And actual C++ users wouldn't benefit from setjmp/longjmp and those
> > #defines, since real exceptions should be raised for C++. I'd say, the
> > best idea for C++ is a wrapper, where al_sound::init would raise an
> > exception.
>
> A C++ wrapper could still raise real exceptions:
>
> al_audio::init()
> {
> al_error_try {
> driver = al_audio_init_driver(NULL);
> }
> al_error_catch {
> throw al_get_last_error();
> }
> }
>
> That also has the benefit of leaving the real throwing in C++, so you needn't
> have to worry about C++ exceptions through C.
Interesting point. So for actual C++ user code (which probably will be
significantly more than C) this would work quite nicely.
> > The TLS error code and NULL return is all that seems needed to me for C.
>
> Then that's all you have to use. Just call al_error_disable_throws() and do it
> the C way.
Well, having to call al_error_disable_throws() for each program would
not look favorably for the API to me. Could always discuss later what
should be default. If it's agreed to have this as default, they I would
try to use it myself though.
> > For the #1 approach, we could have a flag to al_init, like
> > al_init(ABORT_ON_ERROR). And then Allegro would automatically abort on
> > error - just like in your code.
>
> My code has the benefit of being able to turn such aborts on and off at will.
> Like, say, if you want to init video without doing specific error checking,
> but then check the errors while initializing sound. It's also transparent, so
> you could put in a single try/catch around the whole initialization section
> without having to change the initialization code itself.
Yes. In a way it is nice. I just have learned in the past to dislike any
hackish (using setjmp/longjmp always is hackish, and #defines like this
are so even more) features in C code.
>
> That said, however, I do see a /small/ problem with my code. You wouldn't be
> able to jump out from the try block (via goto, a caught exception, another
> longjmp, etc) and continue using Allegro code, or else the code will throw to
> the wrong setjmp point later on. Though I don't think it's that big of a deal
> to simply note that you can't do that, if something like this is used. You
> could always throw a custom allegro error in the try block and check for it
> in the catch block, where you can jump out however you want.
Yes, it shouldn't be a problem normally. A big danger I see is from
something like:
int my_init(void)
{
al_error_try {
....
if (al_audio_init) return -1; // user copy&pasted old init code
....
}
al_error_catch {
return -1;
}
return 0;
}
Or even:
int my_init(void)
{
int i;
for (i = 0; i < modes_count; i++) {
al_error_try {
if (!al_set_gfx_mode(mode[i]))
break;
}
al_error_catch {
continue;
}
}
}
Also this will go wrong in a bad way:
int my_init(void)
{
al_error_catch {
al_audio_init();
}
al_error_try {
}
return 0;
}
Hm, or:
int my_init(void)
{
if (want_sound) {
al_error_try
al_audio_init();
else
printf("If you code python this one will happen to you :P\n");
}
}
In all of those, the C compiler will not even warn.
Something else which might be a problem (probably it's not) - how well
will setjmp/longjmp work when using other languages? E.g. if the
my_init() function really is called from Python. Well, only way to find
out would be to test it.
So, my opinion:
Pro:
- Elegant syntax, almost works like C++ or Python exceptions.
- Could be switched off by default.
- Should also work if user code is in C++.
Con:
- Easy to make very non-obvious mistakes, as is the problem with
many macros trying to add language features to C which it simply does
not have.
- C++ users can as well use a proper C++ wrapper, which can use real
exceptions.
--
Elias Pschernig