From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,790d824907970cc3 X-Google-Attributes: gid103376,public From: Robert A Duff Subject: Re: Exception Propagation Date: 1999/06/14 Message-ID: #1/1 X-Deja-AN: 489452538 Sender: bobduff@world.std.com (Robert A Duff) References: <7jjbl4$n79$1@nnrp1.deja.com> <7jh857$ej$1@nnrp1.deja.com> <375CC549.7EDFB885@spam.com> <0nc73.5376$y6.3195132@WReNphoon3> <7jlud1$l76$1@nnrp1.deja.com> Organization: The World Public Access UNIX, Brookline, MA Newsgroups: comp.lang.ada Date: 1999-06-14T00:00:00+00:00 List-Id: dennison@telepath.com writes: > What I was trying to say is that an exception is *not* propagated into > any task other than the one it occurred in (except in a rendezvous). If > I were to create language TERD, which did have that behavior, then in > TERD it would be completly non-deterministic in the parent task where an > exception raised from the child task popped up. Not necessarily. Tasks synchronize with their parent whenever a master is left. It would make sense to say that at that point, if any dependent tasks died due to unhandled exception, the parent task then raises Tasking_Error (or Program_Error)? Of course, this catches the error rather late, but at least it's not totally ignored. Another idea would be to abort the siblings, and then raise Tasking_Error. But Robert Dewar's idea is best, I think: An unhandled exception in *any* task kills the whole program (hopefully with an error message). It should be a strict language design principle: "Unhandled exceptions never get lost." Or, "The default behavior for run-time errors should be to stop the program". How many times have I run a shell script that printed out an error message, and then continued to bumble along in a confused manner, destroying the evidence and/or valuable data? At least Ada doesn't do that in *most* cases. But Ada does has several other similar cases. For example, an unhandled exception in an interrupt handler is lost. Instead, it should kill the whole program. As Robert pointed out, this puts the burden on the programmer (where it belongs); if the programmer doesn't want the whole program to die, then an exception handler is called for. Another example: an unhandled exception in a Finalize procedure. This case isn't asynchronous, but it has similar problems: many Finalize procedures are happening "together", and if two of them die, we don't know what to do, so we raise Program_Error. The rules for exactly what happens when are way too complicated (I wrote them), and they're extremely difficult to implement efficiently. I think it would have been better if the default behavior for Finalize would be to kill the program; if the programmer wants some other behavior, write a handler. Another example: Storage_Error. It can happen pretty much anywhere, so it's really asynchronous, in a sense. You can pin it down if you look at the machine code, but just looking at the semantics of a given Ada program, it's impossible to predict where it might raise Storage_Error, so there's not much a program can do about it. >... Therefore there would be > no good way to handle and recover from exceptions in child tasks. That's > probably one reason why the designers of Ada did not do that! In Ada > tasks can only get exceptions from themselves or from tasks they > rendezvous with during the rendezvous. Not quite true -- if a child dies before its "begin", then the exception is propagated to the parent. (Well, it's not really "propagated", because it turns into Tasking_Error, because it could happen more than once simultaneously.) All these cases where exceptions get turned into Tasking_Error or Program_Error are fairly useless to handle in most cases -- all the handler knows is "something went wrong". >...That makes it quite > deterministic. That's the key... > As for warning you that a task died, in my experinece most compilers do > *not* do that. Whether that is from concerns about synchronizing writes > to standard output, or from sheer lazieness I can't say. But I know that > both Gnat and GreenHills behave that way, and I suspect ObjectAda does > as well. I'm not sure why, either. I guess people just say, well, the RM says it's not an error, so no error message is warranted. Or maybe people are afraid of failing the ACVC if they give an error message in a non-error situation (I'm not sure they would...), which means you need two different modes, which adds complexity, which maybe isn't worth it. > If you *do* write such code in last-ditch handlers on your tasks, make > sure to handle the IO synchronization problem yourself, or you are > liable to get interspersed output, or different exceptions than the ones > you are looking for. Hmm. Maybe. But the more complicated you make that exception-handling code, the more likely that *it* will have the same problem -- and whose going to handle exceptions in the exception handler? - Bob -- Change robert to bob to get my real email address. Sorry.