Sean O'Rourke: # On Tue, 28 May 2002, Jerome Vouillon wrote: # > That's an interesting point, actually. What is the right # thing to do # > when we run out of memory? # > - Abort immediately. # > This is not very user-friendly. # > - Return a special value. # > But then we need to check the return value of almost all functions # > (including string_compare, for instance). # # I personally dislike this approach, as it requires a large # amount of programming discipline from everyone who works on # the project. The current code indicates that if we took this # approach, we would spend quite a bit of time squashing bugs # from not checking return values in wierd places. It probably # also hurts common-case performance to litter your code with # redundant null-checks as well, but I don't have any data. # # > - Instead of returning a special value, we can set a global variable # > to signal the error. # > Again, we need to check this variable everywhere. # # This by itself seems worse than the above, since it makes # problems even easier to ignore.
OTOH, if all C functions start with a boilerplate like: if(interpreter->flags & PARROT_exception_FLAG) { return NULL; } then this allows us to easily do things like: string_concat(interpreter, string_concat(interpreter, a, b), c); as long as we check for the exception immediately after. In fact, that even lets you delay checking for exceptions so you can centralize things--see below. # > Note that this is the solution adopted by Java. # # Last time I wrote in Java, errors were entirely # exception-based. Have things changed because of the locking # issues you mention below? I assume he means within the JVM's internals. # > - Raise an exception using longjmp. # > But then, if we start using locks all over the place like in Java, # > we are pretty sure to leave the program in an inconsistent state. # # We're currently lock-free, which makes this sound like a good option. I think we just have to say "if you put a lock on something, make sure to set up an exception handler to unlock it and then rethrow the exception". I also think that any way you do it we'll have to wrap it in macros--at least for embedders and extenders. If I ever find a few months of pure boredom, I'd like to try to reimplement Parrot in C++, just to see how much easier it would make things like PMCs; if we have appropriately set up macros, we can hide from the user the actual implementation of exceptions: #define PARROT_TRY /* nothing */ #define PARROT_CATCH if(interpreter->flags & PARROT_exception_FLAG) ... PARROT_TRY { d=string_concat(interpreter, string_concat(interpreter, a, b), c); ... } PARROT_CATCH { (code) } Just change the macros to: #define PARROT_TRY try #define PARROT_CATCH catch(void* PARROT_CATCH_this_is_unused) for C++, or: #define PARROT_TRY if(!setjmp()) #define PARROT_CATCH else for setjmp/longjmp. (Yes, I know that's not the way setjmp is really used, but you get the idea.) For short stretches of code, I'd imagine that PARROT_TRY d=string_concat(interpreter, string_concat(interpreter, a, b), c) PARROT_CATCH Parrot_fputs(interpreter, Parrot_stderr, "We're screwed!"); (assuming that C++'s try and catch can take statements instead of blocks, anyway--although even if they don't, it's just four more characters.) --Brent Dax <[EMAIL PROTECTED]> @roles=map {"Parrot $_"} qw(embedding regexen Configure) blink: Text blinks (alternates between visible and invisible). Conforming user agents are not required to support this value. --The W3C CSS-2 Specification