# FlipFlop Voodoo

Discussion in 'Ruby' started by Daniel Nugent, Jul 3, 2005.

1. ### Daniel NugentGuest

So I was reading through the retrospective on RedHanded today and saw
the piece of flipflops
(http://redhanded.hobix.com/inspect/hopscotchingArraysWithFlipFlops.html).

Reading it I realized that I didn't quite understand how the
flipfloperator worked exactly. So I grabbed the Pickaxe2 and read
that it returns true when the state machine is in the set state at the
end of the call.

Looking at both why's examples, the ones in Pickaxe2, and through a
little experimentation of my own and once again reviewing the state
transition diagram in Pickaxe2, I figured there must be a typo.

See example 1 on pg 342:

a =3D (11..20).collect {|i| (i%4 =3D=3D 0)..(i%3 =3D=3D 0) ? i ? nil}
a -> [nil, 12, nil, nil, nil, 16, 17, 18, nil, 20]

If there isn't a typo and I'm reading it right, then 18 should not be
in the output array since the second part of the flipflop should have
triggered the state machine to go back to the unset state. Now,
Pickaxe2 mentions that when the second condition evaluates to true on
the same call as the first condition, it will still output true
anyhow.

However, it does not explain why this happens or why it also outputs
18 even though 18%3=3D=3D0 should evaluate to true and push the state
machine into the unset state.

someone taking the time to explain it more thoroughly Because I
*think* I understand what's going on here, but my reading of Pickaxe2
would seem to indicate that I don't.
--=20
-Dan Nugent

Daniel Nugent, Jul 3, 2005

^
Typo here ------------------------------------------'

Should be ":", of course. It's unrelated to what you're asking, anyway=
;-)
The "problem" here is that two dot ranges _include_ the ending. What I
don't quite understand is this

--------------------------------- 8< ---------------------------------
[email protected]:~/tmp\$ cat >number_list
one
two
three
four
five
[email protected]:~/tmp\$ irb
irb(main):001:0> File.foreach('number_list') do |line|
irb(main):002:1* if line =3D~ /two/ .. line =3D~ /four/
irb(main):003:2> puts "#{line.chomp} is included in the two..four r=
ange"
irb(main):004:2> end
irb(main):005:1> if line =3D~ /two/ ... line =3D~ /four/
irb(main):006:2> puts "#{line.chomp} is included in the two...four
range"
irb(main):007:2> end
irb(main):008:1> end
two is included in the two..four range
two is included in the two...four range
three is included in the two..four range
three is included in the two...four range
four is included in the two..four range
four is included in the two...four range
=3D> nil
irb(main):009:0> (1..20).to_a
=3D> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, =
20]
irb(main):010:0> (1...20).to_a
=3D> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
--------------------------------- >8 ---------------------------------

It seems that ranges in conditions always behave as "..", even if you use=
the
"..." operator. Another, simpler, example:

--------------------------------- 8< ---------------------------------
irb(main):007:0> (1..20).each do |i|
irb(main):008:1* puts i if (i =3D=3D 4 .. i =3D=3D 5)
irb(main):009:1> end
4
5
=3D> 1..20
irb(main):010:0> (1..20).each do |i|
irb(main):011:1* puts i if (i =3D=3D 4 ... i =3D=3D 5)
irb(main):012:1> end
4
5
=3D> 1..20
--------------------------------- >8 ---------------------------------

Is there any reason for this? Is it a bug?

--=20
Esteban Manchado Vel=E1zquez <> - http://www.foton.es
EuropeSwPatentFree - http://EuropeSwPatentFree.hispalinux.es

Esteban Manchado Velázquez, Jul 3, 2005

3. ### Daniel NugentGuest

I think you're wrong here in that you've misunderstood what the
purpose of the conditional range operator is.

For one, there's no typo in my original message (I'm copying right out
of Pickaxe2)

Here's the first example they give:

a =3D (11..20).collect {|i| (i%4 =3D=3D0)..(i%3 =3D=3D 0) ? i : nil)
a -> [nil, 12, nil, nil, nil, 16, 17, 18, nil, 20]

Here, when i =3D 12, we can see that the first expression evaluates to
true and the second expression evaluates to true. If the state
machine moves each time one part of the expression evaluated to true,
then it wouldn't print 12 since it would be back in the unset state
(where it was before the first expression evaluated to true). The
Pickaxe mentions this, that if they both evaluate on the same call it
will finish in the unset state but the flipflop operator would still
return true in that condition. However, when i =3D 16, it stays in the
set state until i =3D 18, when the state machine should go back to the
unset state and *not* return true if the Pickaxe is to be believed.

a =3D (11..20).collect {|i| (i%4 =3D=3D0)...(i%3 =3D=3D 0) ? i : nil)
a -> [nil, 12, 13, 14, 15, 16, 17, 18, nil, 20]

Here, when i =3D 12, the first expression evaluates to true, *but the
second expression doesn't get a chance to*. Pickaxe2 states that the
semantics of conditional ... causes a short circuit when the first
expression evaluates to true. Thus, i%3 does not evaluate to 0 until
i =3D 15. Once again, were the pickaxe to be believed, this should move
the state machine into the unset state and the flipflop operator
should not return true.

If conditional ... worked as you expected, then 12-15 should be nil in
the above example since ... would exclude 12 since it's the end of the
range (1...1.to_a =3D=3D [] for example)

So, basically, I think I understand the semantics of it, just that
there's a small error in Pickaxe2's explanation. It should say
something like if expression2 is evaluated to true, the state machine
is moved to the unset state after the operator has decided to return
true.

--=20
-Dan Nugent

Daniel Nugent, Jul 3, 2005
4. ### Michael CampbellGuest

Not to be a pedant, but yes, there was. Here's your original:
The second "?" should be ":".

Michael Campbell, Jul 3, 2005
5. ### Hal FultonGuest

So, you've got something against pedants?

Hal

Hal Fulton, Jul 3, 2005
6. ### Daniel NugentGuest

Whoops, you're right about that Michael, the carat being near the
second modulo operator confused me, didn't see the second question
mark at all.

Sorry. I maintain my points otherwise.

--=20
-Dan Nugent

Daniel Nugent, Jul 4, 2005