?

Log in

No account? Create an account
find the bug - brad's life — LiveJournal [entries|archive|friends|userinfo]
Brad Fitzpatrick

[ website | bradfitz.com ]
[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

find the bug [Nov. 8th, 2004|02:36 pm]
Brad Fitzpatrick
We discovered yesterday that almost all comments in the past year in the database have metadata attached to them saying, "No subject icon!", which is useless... that's the default.

Whitaker found the bug:
1.45 (martine 08-Jul-03): my $subjecticon = "";
1.45 (martine 08-Jul-03): if ($form->{'subjecticon'} ne "none" ||
                              $form->{'subjecticon'} ne "") {
1.45 (martine 08-Jul-03):     $subjecticon = LJ::trim(lc($form->{'subjecticon'}));
1.45 (martine 08-Jul-03): }

Heh.
LinkReply

Comments:
[User Picture]From: alister
2004-11-08 10:45 pm (UTC)
bad martine, no cookie.
(Reply) (Thread)
[User Picture]From: nefarious
2004-11-08 10:53 pm (UTC)
haha Evan got pwned.
(Reply) (Thread)
[User Picture]From: adamthebastard
2004-11-08 11:18 pm (UTC)
for the record it's supposed to be AND in the condition statement right?
(Reply) (Thread)
[User Picture]From: brad
2004-11-09 01:08 am (UTC)
Yup
(Reply) (Parent) (Thread)
[User Picture]From: bostonsteamer
2004-11-08 11:24 pm (UTC)
<3 cvs blame
(Reply) (Thread)
[User Picture]From: taral
2004-11-08 11:24 pm (UTC)
?
(Reply) (Thread)
From: evan
2004-11-08 11:36 pm (UTC)
|| vs &&
(Reply) (Parent) (Thread)
[User Picture]From: taral
2004-11-09 12:22 am (UTC)
*snicker* "Warning: Condition is always true."
(Reply) (Parent) (Thread)
(Deleted comment)
From: evan
2004-11-08 11:35 pm (UTC)
:~(
(Reply) (Thread)
[User Picture]From: mpnolan
2004-11-08 11:47 pm (UTC)
How would you write a while loop to continuously input numbers a and b until both a and b are not 0?

Seems simple, and the first thing I wrote was:

a = 1
b = 1
while (a != 0 && b != 0)
{
}

My friend did the same thing. If you think this is right, try letting a=0, b=1.
(Reply) (Thread)
[User Picture]From: adamthebastard
2004-11-09 01:46 am (UTC)
It's really how you worded the problem that led you to write the busted logic.

When I read the question I wrote: "while( !(a==0 && b==0) ) {}" which suffers from the same problem.

If you had worded the problem "How would you write a while loop to continuously input numbers a and b until neither a nor b are 0?". You probably would have come up with this: "while( a==0 || b==0 ) {}".
(Reply) (Parent) (Thread)
[User Picture]From: 3smallishmagi
2004-11-14 11:17 am (UTC)
So knowing multiple people had been tricked by this, I thought hard and got
a=0; b=0;
while((a==0)||(b==0)){...}

We have an answer, but we're stuck with the same problem of knowing whether its right or not. It's clear that you, me and the half dozen of so people who have tried this are too stupid to write this sort of code reliably, so what do we do?

We break the problem down into smaller, more digestible problems, we try to solve one problem at a time, because if you try to solve two, you have to simultaneously think about those two and the interactions of those solutions, we use recipe code that we have used often and understand completely, we use theory to simplify things.

How does that apply here?
The problem statement is "How would you write a while loop to continuously input numbers a and b until both a and b are not 0?"
some 'theory' is that not( A OR B ) === not A AND not B / not( A AND B) === not A OR not B

the problem asks for a while loop:
while(CONDITION){}


that continuously inputs two numbers
while(CONDIDION){
   read(a);
   read(b);

}


which has a bug because there is a point where we may continue to input numbers after the exit condition is true, so:
while(CONDIDION){
   read(a);
   if(!CONDITION)break;
   read(b);
}


This is already not ideal code because we have code duplication, but I can't see a better way right now, and how are we going to be sure its right when we're done? We could use proofs, but I'm not sure I can use the stuff I've been taught reliably, and I don't think there are many who can. We can use comments to tie the problem statement to the code

// read a and b until not CONDITION
while(CONDIDION){
   read(a);
   if(!CONDITION)break;
   read(b);
}


So, What is CONDITION?
"read a and b until both a and b are not 0"
which is
until (a!=0) && (b!=0)

but there's a not in the way we've expressed things so far so lets get rid of it and use a more familiar pattern of while(!done){do stuff}

// read a and b until (a!=0)  && (b!=0)
done= (a!=0)  && (b!=0);
while(!done){
   read(a);
   done=(a!=0)  && (b!=0)
   if(done)break;
   read(b);
   done=(a!=0)  && (b!=0)
}


which makes one twitch from all the duplication. Perhaps a helper function, and importantly, giving it a good name.
int allNonZero(a,b){ return  (a!=0) && (b!=0) ; }
...
// read a and b until (a!=0)  && (b!=0)
while(!allNonZero(a,b)){
   read(a);
   if(allNonZero(a,b))break;
   read(b);
}


which is finally something that solves the problem and is clearly correct.

Ok, so I'm not sure about the 'clearly' bit. I see it transforms to my original code, but its a lot longer and has more nots and logic, and so by the definitions I tend to use, it's more difficult to understand and more complicated, and I'm going to go to bed now ( I wrote this all out in ridiculous longhand mostly for my own amusement to see how it would turn out and I'm still not happy with the original problem which converts
if(true)$subjecticon = LJ::trim(lc($form->{'subjecticon'}));


to
my $subjecticon = "";
if ($form->{'subjecticon'} ne "none" &&
    $form->{'subjecticon'} ne "") {
  $subjecticon = LJ::trim(lc($form->{'subjecticon'}));
}

which makes $subjecticon have values either "" or LJ::trim(lc($form->{'subjecticon'}))
Assuming LJ::trim(lc("")) == "". It would appear to be equivalent to
$subjecticon = LJ::trim(lc($form->{'subjecticon'}));
$subjecticon= "" if $form->{'subjecticon'} eq "none"

)

(Reply) (Parent) (Thread)