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: fac41,9a0ff0bffdf63657 X-Google-Attributes: gidfac41,public X-Google-Thread: f43e6,9a0ff0bffdf63657 X-Google-Attributes: gidf43e6,public X-Google-Thread: 103376,4b06f8f15f01a568 X-Google-Attributes: gid103376,public X-Google-Thread: 1108a1,9a0ff0bffdf63657 X-Google-Attributes: gid1108a1,public From: Matthew Heaney Subject: Re: Software landmines (loops) Date: 1998/09/01 Message-ID: #1/1 X-Deja-AN: 386740630 Sender: matt@mheaney.ni.net References: <35f51e53.48044143@ <6sf4gl$hb6@flatland.dimensional.com> NNTP-Posting-Date: Tue, 01 Sep 1998 03:35:34 PDT Newsgroups: comp.lang.eiffel,comp.object,comp.software-eng,comp.lang.ada Date: 1998-09-01T00:00:00+00:00 List-Id: jtc@dimensional.com (Jim Cochrane) writes: > How about the following version, without multiple exit points (written in > Eiffel because it is a good language for this style [it actually doesn't > allow the multiple return style] and because I'm familiar with Eiffel.) > > class STACK [G] ... > is_equal (other: STACK [G]): BOOLEAN is > -- Are all items in Current equal to all item in other? > require > other /= Void > local > i1, i2: STACK_ITERATOR > do > !!i1.make (Current); !!i2.make (other) > from > i1.start; i2.start > until > i1.after or i2.after or else i1.item /= i2.item > loop > i1.forth; i2.forth > end > Result := i1.after and i2.after > end > > I don't think this is particularly hard to understand or maintain, > plus it is simpler than the algorithm below - it eliminates the if > statement at the beginning. (STACK_ITERATOR behavior is, hopefully, > obvious - i.item means the value of item at the current cursor > position of i.) I threw this together just for this post, so > apologies if there are any bugs (and bonus points to those that find > them :-) ). I realized I had a compare op lying around implemented using the same idea: using iterators to simultaneously traverse over a pair of collections. As you can see, it's more or less like the earlier example I posted. (At least I'm consistent.) It avoids the mental gymnastics required to understand the (Eiffel) example shown above, because there isn't any complicated loop predicate. The conditions under which the loop terminates should be pretty obvious. Find a mismatch between items, and just bail out. Pure and simple. function ACL.Compare (Left : access Left_Collection; Right : access Right_Collection) return Boolean is Length : Natural renames Get_Length (Left.all); Left_Iter : Left_Iterator (Left); Right_Iter : Right_Iterator (Right); begin -- Compare if Length /= Get_Length (Right.all) then return False; end if; for Index in 1 .. Length loop if Get_Item (Left_Iter).all /= Get_Item (Right_Iter).all then return False; end if; Advance (Left_Iter); Advance (Right_Iter); end loop; return True; end ACL.Compare;