<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Tomáš Matoušek's Weblog &#187; Ruby features</title>
	<atom:link href="http://matousek.wordpress.com/category/ruby-features/feed/" rel="self" type="application/rss+xml" />
	<link>http://matousek.wordpress.com</link>
	<description>IronRuby, DLR, .NET Framework</description>
	<lastBuildDate>Sun, 11 Dec 2011 19:50:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='matousek.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/545371f672fc051653bf088e1b9b73ec?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Tomáš Matoušek's Weblog &#187; Ruby features</title>
		<link>http://matousek.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://matousek.wordpress.com/osd.xml" title="Tomáš Matoušek&#039;s Weblog" />
	<atom:link rel='hub' href='http://matousek.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Ruby flip-flop operator</title>
		<link>http://matousek.wordpress.com/2008/12/06/ruby-flip-flop-operator/</link>
		<comments>http://matousek.wordpress.com/2008/12/06/ruby-flip-flop-operator/#comments</comments>
		<pubDate>Sun, 07 Dec 2008 02:12:29 +0000</pubDate>
		<dc:creator>tomasmatousek</dc:creator>
				<category><![CDATA[Ruby features]]></category>

		<guid isPermaLink="false">http://matousek.wordpress.com/2008/12/06/ruby-flip-flop-operator/</guid>
		<description><![CDATA[Although its usage is discouraged the flip-flop operator – a range used in a condition – is still a Ruby language feature. Let&#8217;s take a look at how IronRuby implements it. First, we need to figure out what exactly it is supposed to do. The general behavior is described in books on Ruby, however to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=matousek.wordpress.com&#038;blog=5595917&#038;post=12&#038;subd=matousek&#038;ref=&#038;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Although its usage is discouraged the <i><a target="_blank" href="http://www.rubycentral.com/pickaxe/tut_expressions.html#S6">flip-flop operator</a></i> – a range used in a condition – is still a Ruby language feature. Let&#8217;s take a look at how IronRuby implements it. First, we need to figure out what exactly it is supposed to do. The general behavior is described in books on Ruby, however to implement it in a compiler you need to sort out all the edge cases. So let&#8217;s play with it a little.</p>
<h5>What distinguishes a flip-flop from a range?</h5>
<p>The syntax is the same: <i>expression</i> ‘..’ <i>expression</i> (end-inclusive range) or <i>expression</i> ‘&#8230;’ <i>expression</i> (end-exclusive range). A range is considered a flip-flop operator if any of its bound is not an integer literal and if it is used as a <i>condition</i> of the following expressions:</p>
<ul>
<li><i>condition</i> ‘?’ <i>expression</i> ‘:’ <i>expression</i> </li>
<li><i>statement</i> ‘if’ <i>condition</i> </li>
<li><i>statement</i> ‘unless’ <i>condition</i> </li>
<li><i>statement</i> ‘while’ <i>condition</i> </li>
<li><i>statement</i> ‘until’ <i>condition</i> </li>
<li>‘if’ <i>condition</i> <i>then</i> <i>statements</i> <i>if-tail</i> ‘end’ </li>
<li>‘unless’ <i>condition</i> <i>then</i> <i>statements</i> <i>else-opt</i> ‘end’ </li>
<li>‘while’ <i>condition </i>‘do’ <i>statements</i> ‘end’ </li>
<li>‘until’ <i>condition </i>‘do’ <i>statements</i> ‘end’ </li>
</ul>
<p>For example:</p>
<pre>irb(main):001:0&gt; 1 if TRUE..FALSE 
=&gt; 1</pre>
<p>In addition, parenthesized ranges used in a condition are also flip-flops, e.g.: </p>
<pre>irb(main):001:0&gt; 1 if (TRUE..FALSE) 
=&gt; 1</pre>
<p>‘(‘ <i>statements</i> ‘)’ is a <i>block expression</i> with a single statement expression TRUE..FALSE. If there are more statements in the block in front of the range it is no longer a flip-flop operator:</p>
<pre>irb(main):008:0&gt; 1 if (puts;TRUE..FALSE) 
ArgumentError: bad value for range </pre>
<p>The exception is raised since a range bounds cannot be Booleans.</p>
<p>Any number of nested <i>block expressions</i> works:</p>
<pre>irb(main):001:0&gt; 1 if ((((TRUE..FALSE)))) 
=&gt; 1 </pre>
<p>And <i>begin</i>-<i>end</i> blocks work as well: </p>
<pre>irb(main):032:0&gt; 1 if begin TRUE..FALSE end 
=&gt; 1 </pre>
<p>As do any combinations of the two (but only in Ruby 1.9, in Ruby 1.8.6 some combinations don’t work, which I consider a bug):</p>
<pre>irb(main):001:0&gt; 1 if (begin (((begin begin TRUE..FALSE end end))) end) 
=&gt; 1 </pre>
<p>Also, ranges used in Boolean expressions used as conditions are considered flip-flops: </p>
<pre>irb(main):018:0&gt; 1 if t(1)..f(2) and not t(3)..f(4) or t(5)..f(6) 
123456=&gt; 1 
irb(main):018:0&gt; 1 if (t(1)..f(2)) &amp;&amp; !(t(3)..f(4)) || (t(5)..f(6)) 
123456=&gt; 1 </pre>
<p>where <i>t</i> and <i>f</i> are functions that print the argument and return <i>true</i> and <i>false</i> respectively. The second example also doesn’t work in Ruby 1.8.6, oups. </p>
<p>Let’s summarize what have we just found out: block expressions (parenthesized or <i>begin-end</i>) containing a single range and Boolean expressions propagate the “in-condition” property to their children AST nodes. The “in-condition” property then turns ranges into flip-flop operators. Other nodes don’t propagate it. A <em>method call </em>doesn’t, for example: </p>
<pre>irb(main):018:0&gt; 1 if puts(t(1)..f(2)) 
ArgumentError: bad value for range </pre>
<p>Side note: this property is also applied on regular expressions. If a regex is “in-condition” it is compiled as a match against $_ variable: </p>
<pre>irb(main):029:0&gt; $_ = 'xz' 
=&gt; &quot;xz&quot; 
irb(main):030:0&gt; 1 if /y/ or ((begin((/x/ and /(z)/))end)) 
=&gt; 1 
irb(main):031:0&gt; $1 
=&gt; &quot;z&quot; </pre>
<h5>How does flip-flop work?</h5>
<p>We know from the books that flip-flop would probably define some state variable that changes values as the expressions of the operator are evaluated. To figure out how exactly it works I wrote a simple script:</p>
<pre>F = false
T = true
x = X = '!'

B = [F,T,x,x,x,T,x,F,F]
E = [x,x,F,F,T,x,T,x,x]
       
def b
  step('b',B)
end

def e
  step('e',E)
end

def step name,value
  r = value[$j]
  puts &quot;#{$j}: #{name} -&gt; #{r.inspect}&quot;
  
  $j += 1
  
  $continue = !r.nil?  
  r == X ? raise : r  
end

$j = 0
$continue = true
while $continue
  if b..e 
    puts &quot;#{$j}: TRUE&quot; 
  else
    puts &quot;#{$j}: FALSE&quot; 
  end
end</pre>
<p>In this code we evaluate an end-inclusive flip-flop in a loop. Each time the flip-flop operator is evaluated ‘b’ or ‘e’ method is called, or both methods are called. Global variable $j is an index into B and E arrays defined at the top. The arrays define a sequence of values the methods <i>b</i> and <i>e</i> should return. If <i>x</i> value (‘!’) is to be returned an exception is thrown. This way we can track what the automaton behind the flip-flop operator does. Using the output of the script we can easily deduce how the automaton could look like:</p>
<pre>0: b -&gt; false
1: FALSE
1: b -&gt; true
2: TRUE
2: e -&gt; false
3: TRUE
3: e -&gt; false
4: TRUE
4: e -&gt; true
5: TRUE
5: b -&gt; true
6: TRUE
6: e -&gt; true
7: TRUE
7: b -&gt; false
8: FALSE
8: b -&gt; false
9: FALSE
9: b -&gt; nil
10: FALSE.</pre>
<p><a href="http://matousek.files.wordpress.com/2008/12/flipflop.png"><img style="border-bottom:0;border-left:0;display:inline;border-top:0;border-right:0;" title="Flip-Flop" border="0" alt="Flip-Flop" src="http://matousek.files.wordpress.com/2008/12/flipflop-thumb.png?w=304&h=258" width="304" height="258" /></a> </p>
<p>It has four states: BEFORE, INSIDE, AFTER and a lambda state. In each state <i>b</i> or <i>e</i> expression is evaluated and the automaton transitions to another state based upon the result: <i>true</i> (T) or <i>false</i> (F). If it transitions to INSIDE or AFTER state the flip-flop operator returns <i>true</i>. If it transitions to BEFORE state the operator returns <i>false</i>. If it transitions to the lambda state the operator evaluates <i>b</i> and does one more transition. </p>
<p>The previous automaton works for an end-inclusive flip-flop operator. The one bellow does for an end-exclusive operator – the lambda state is gone: </p>
<p><a href="http://matousek.files.wordpress.com/2008/12/flipflopexclusive.png"><img style="display:inline;" title="Flip-Flop-Exclusive" border="0" alt="Flip-Flop-Exclusive" src="http://matousek.files.wordpress.com/2008/12/flipflopexclusive-thumb.png?w=304&h=258" width="304" height="258" /></a> </p>
<h5>What code does IronRuby emit?</h5>
<p>We emit the following code for end-inclusive flip-flop operator {begin}..{end}: </p>
<pre>if state || IsTrue({begin})
  state = IsFalse({end})
  true
else  
  false
end  </pre>
<p>The state variable is a Boolean and it’s <em>true </em>iff the automaton is in INSIDE or lambda state. In both states this means evaluate {end}<em> </em>expression, transition to the state given by negated result and return <em>true</em>. If the state variable is <em>false</em> we are either in AFTER or in BEFORE state. In any case {begin} is evaluated. If it returns <em>false</em> we go to/stay in BEFORE state and the result of the flip-flop operator is <em>false</em>. Otherwise we go to the lambda state and evaluate <em>end</em>.</p>
<p>Similarly, the end-exclusive flip-flop operator {begin}&#8230;{end} is implemented as</p>
<pre>if state
  state = IsFalse({end}) 
  true
else
  state = IsTrue({begin})
end</pre>
<p>&#160;</p>
<p>The state variable is allocated in the inner-most method scope. A flip-flop operator used in a block preserves the state across multiple calls to the block:</p>
<pre>def y *a; yield *a; end

def test
  $p = proc { |b,e|
    puts b..e ? TRUE : FALSE
  }
  
  y false, &amp;$p  
  y true, true, &amp;$p
  y false, &amp;$p
  y true, false, &amp;$p
end

test</pre>
<p>Output:</p>
<pre>false 
true 
false 
true </pre>
<p>The method that transforms IronRuby’s RangeExpression node into DLR AST in the case the range is a flip-flop operator looks like:</p>
<pre class="csharpcode"><span class="kwrd">private</span> MSA.Expression<span class="rem">/*!*/</span> TransformReadCondition(AstGenerator<span class="rem">/*!*/</span> gen) {
    <span class="rem">// Define state variable in the inner most method scope.</span>
    <span class="kwrd">var</span> stateVariable = gen.CurrentMethod.Builder.DefineHiddenVariable(<span class="str">&quot;#in_range&quot;</span>, <span class="kwrd">typeof</span>(<span class="kwrd">bool</span>));

    <span class="kwrd">var</span> begin = Ast.Box(_begin.TransformRead(gen));
    <span class="kwrd">var</span> end = Ast.Box(_end.TransformRead(gen));

    <span class="kwrd">if</span> (_isExclusive) {
        <span class="kwrd">return</span> Ast.Condition(
            stateVariable,
            Ast.Comma(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.True()),
            Ast.Assign(stateVariable, Methods.IsTrue.OpCall(begin))
        );  
    } <span class="kwrd">else</span> {
        <span class="kwrd">return</span> Ast.Condition(
            Ast.OrElse(stateVariable, Methods.IsTrue.OpCall(begin)),
            Ast.Comma(Ast.Assign(stateVariable, Methods.IsFalse.OpCall(end)), Ast.True()),
            Ast.False()
        );
                          
    }
}</pre>
<p>This code can be found in <i>Ruby\Compiler\Ast\Expressions\RangeExpression.cs.</i> Propagation of “in-condition” property to AST nodes is performed by <i>ToCondition</i> virtual method overridden by RangeExpression, RegularExpression, AndExpression, OrExpression and BodyExpression and called from parser (<i>Ruby\Compiler\Parser\Parser.y</i>). </p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/matousek.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/matousek.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/matousek.wordpress.com/12/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=matousek.wordpress.com&#038;blog=5595917&#038;post=12&#038;subd=matousek&#038;ref=&#038;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://matousek.wordpress.com/2008/12/06/ruby-flip-flop-operator/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="" medium="image">
			<media:title type="html">tomasmatousek</media:title>
		</media:content>

		<media:content url="http://matousek.files.wordpress.com/2008/12/flipflop-thumb.png" medium="image">
			<media:title type="html">Flip-Flop</media:title>
		</media:content>

		<media:content url="http://matousek.files.wordpress.com/2008/12/flipflopexclusive-thumb.png" medium="image">
			<media:title type="html">Flip-Flop-Exclusive</media:title>
		</media:content>
	</item>
	</channel>
</rss>
