Path: csiph.com!news.mixmin.net!eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Libraries using longjmp for error handling Date: Fri, 29 Sep 2023 21:56:02 -0700 Organization: A noiseless patient Spider Lines: 92 Message-ID: <86cyy0fee5.fsf@linuxsc.com> References: <65SQM.565977$9o89.411905@fx05.ams4> <871qejf62x.fsf@bsb.me.uk> <86y1gphiur.fsf@linuxsc.com> <877co9d8m2.fsf@bsb.me.uk> <86bkdlghqr.fsf@linuxsc.com> <8734ywbvek.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: dont-email.me; posting-host="a99bceb92abacf1e025e751f28ca3812"; logging-data="761663"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/7hnnvPa4YK5hJq9ErRuV4fCdwfF1ZV2w=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:Cb6PFJJBJkfZBVFrXasslttpgNU= sha1:LYcUGZJB1MV0Q9McMVxhDIkUEIQ= Xref: csiph.com comp.lang.c:176778 Ben Bacarisse writes: > Tim Rentsch writes: > >> Ben Bacarisse writes: >> >> [..how should errors be handled..] >> >>> How would you prefer these sorts of thing to be signalled? >> >> Let me give just one example. >> >> I wrote some code not long ago to add a value to a set of values, >> where the set is represented using a recursive binary tree structure >> (like red-black trees, but a little different). Usually we may >> expect that a request to add a value would offer a value not already >> included in the set, but certainly it can happen that there is a >> call to add a value that is already included, in which case the top >> level return value should be the original tree structure. >> >> I thought it would be easier to write a simple recursive routine >> that assumes the to-be-added value is not yet included in the set, >> and if that assumption is violated raise an exception that is caught >> at the outermost level and simply returns the original argument tree >> value. Certainly the code could have been written to handle the >> already-present situation at each level of the recursion, but it was >> much easier and much cleaner to handle it by raising an exception. > > This is one of those cases where I just have to take your word for it, > (and I am happy to do that). Responding here to just this one part. Here is a simpler version of the code, for an ordinary binary tree, and without any rebalancing: module TreeSet = struct type 'a treeset = Empty | Node of 'a treeset * 'a * 'a treeset exception Present let add tree element = let rec add t e = match t with | Empty -> Node( Empty, e, Empty ) | Node( a, v, b ) -> if e < v then Node( add a e, v, b ) else if e > v then Node( a, v, add b e ) else raise Present in try add tree element with Present -> tree end Transliterating that into C, the central functions might look like this (I have left out the type definition and the constructor function used to build a new node value): static Tree add( jmp_buf, Tree, double ); static Tree raise_present( jmp_buf ); static Tree new_node( Tree, double, Tree ); Tree add_element( Tree tree, double new_element ){ jmp_buf jb; if( setjmp( jb ) ) return tree; return add( jb, tree, new_element ); } Tree add( jmp_buf jb, Tree t, double d ){ return ! t ? new_node( 0, d, 0 ) : d < t->v ? new_node( add( jb, t->a, d ), t->v, t->b ) : d > t->v ? new_node( t->a, t->v, add( jb, t->b, d ) ) : /*********/ raise_present( jb ); } Tree raise_present( jmp_buf jb ){ longjmp( jb, 1 ); } Of course it's unlikely that sets would be implemented this way in C, but that's not the point; the point is that exceptions can result in code that is cleaner and easier to understand than an alternate approach where return values would have to be checked at every level. (Incidentally, I want to acknowlege you comment about taking my word for the result. I still thought it would be good to give a concrete example, even if it is a very simplified one.)