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: 1108a1,9a0ff0bffdf63657 X-Google-Attributes: gid1108a1,public X-Google-Thread: 103376,4b06f8f15f01a568 X-Google-Attributes: gid103376,public From: Matthew Heaney Subject: Re: Software landmines (loops) Date: 1998/09/01 Message-ID: #1/1 X-Deja-AN: 386689387 Sender: matt@mheaney.ni.net References: <35f51e53.48044143@ <6sf4gl$hb6@flatland.dimensional.com> NNTP-Posting-Date: Mon, 31 Aug 1998 22:28:21 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: > 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 think this is a real brain teaser. Let me show you how I try to unravel it. Let's start by making a decision table for the loop predicate: 1 2 3 4 5 6 7 8 i1.after T T T T F F F F i2.after T T F F T T F F i1.item /= i2.item T F T F T F T F As you can see, there are 8 rules, which just exceeded the cognitive limits of most of human population. Already, we're in trouble. But there's more trouble ahead. The last part of the predicate uses a short-circuit form, so we're going to have to prune the table, by removing the rules in which i1.after and i2.after are both false. Or is it both true??? As I'm writing this post, I've already spent several minutes trying to figure out when the last part of the predicate actually gets executed. And I don't even know what the evaluation order rules are in Eiffel. Does i1.after or i2.after or else i1.item /= i2.item mean (i1.after or i2.after) or else i1.item /= i2.item or i1.after or (i2.after or else i1.item /= i2.item) Hmmm? Maybe these expressions both have the same value. I don't know, but I'm obligated to find out. This is mental work I shouldn't have to do, and I'll probably get it wrong. So I gotta ask: Is this a program, or an IQ test? I'll just use my little decision table friend again, to help me crack the secret of what result the predicate acually delivers. 1 2 3 4 5 6 7 8 i1.after T T T T F F F F i2.after T T F F T T F F i1.item /= i2.item - - - - - - T F The dash (-) means "does not matter." So the item test only influences the result (I think) when i1.after and i2.after are both false. (Gee, that's what I originally thought. A miracle happened, and I guessed right! But how many other times will I be this lucky?) Now I have to actually figure out what the result of the predicate is: 1 2 3 4 5 6 7 8 i1.after T T T T F F F F i2.after T T F F T T F F i1.item /= i2.item - - - - - - T F predicate has value T T T T T T T F Ah, so that's the secret! The loop teriminates (I think) when all sub-predicates yield false. Revealed at last, after several minutes of careful analysis, which I probably screwed up. But wait, I did screw up! Loop termination in Eiffel has opposite the traditional sense, which is to terminate when the predicate is false. So the loop terminates when the predicate is true. Whew! How many programmers do you think will take the time to figure all this out? How many programmers even know how to use a decision table? One more issue with this example. Following termination, calculating the result, Result := i1.after and i2.after means i1.after and i2.after get tested again. Why? They were tested already, in the loop. Why test them twice? Maybe I get bonus points for being able to decipher this, but is that how we should write software? Be rewarding those who perform mental gymnastics? I hope not.