tag:blogger.com,1999:blog-29998792599199099562024-03-09T03:12:58.020+02:00Flex LambdaExploring the functional perspective in Flex and Actionscript 3.0Rabih Kodeihhttp://www.blogger.com/profile/16576945032271430312noreply@blogger.comBlogger2125tag:blogger.com,1999:blog-2999879259919909956.post-32838131926155492852009-09-09T22:02:00.001+03:002009-12-03T17:00:57.555+02:00Implementing Undo/Redo using Closures<p align="justify">Today, I was thinking about adding undo/redo functionality in a form editor I have been working on lately. So I decided to look around to see if there are any libraries or implementations I could use. Couldn’t find anything to my liking, most of them use elaborate patterns (<a href="http://www.as3dp.com/2008/01/24/actionscript-30-memento-design-pattern-encapsulating-saved-states/">memento</a>, etc….) or simply resort to saving the whole application state which is overkill, so I developed my own undo/redo thing.</p> <span class="fullpost"> <p align="justify">In any Flex application, when you perform an action against some component, what you are actually doing is applying a <em>forward transformation</em> to the application state at one time to produce a different state at another time. Likewise, when an <em>inverse transformation</em> is applied to the current application state, we end-up with the original state.</p> <p align="justify">The main idea is to simply use a closure to capture any transformation with all the necessary data which are used in the transformation logic. The result of this will be a <em>stateless</em> function that can be called any time. Thus for undo/redo, the forward transformation and its reverse are captured resulting in two distinct stateless functions. Both of undo and redo functions could be stored in an array and called at will without worrying about the current state of the application. </p> <p align="justify">But what are the conditions that would ensure the consistency of the application state with the undo/redo logic at all times? Basically just one, it is the requirement that <strong><em>every</em></strong> action performed in the application be captured in a separate closure.</p> <p align="justify">For example:</p> <p align="justify"><embed src="http://sites.google.com/site/fileimageserver/files/undo_redo.swf?attredirects=0" quality="high" allowscriptaccess="always" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" align="middle" height="162" width="349"></embed></p> <p align="justify">for which the code is:</p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" nowrap="nowrap" align="left"><code><font color="#000000"><?xml version=</font><font color="#990000"><b>"1.0" </b></font><font color="#000000">encoding=</font><font color="#990000"><b>"utf-8"</b></font><font color="#000000">?></font> <br /><font color="#000000"><mx:Application xmlns:mx=</font><font color="#990000"><b>"http://www.adobe.com/2006/mxml" </b></font><font color="#000000">layout=</font><font color="#990000"><b>"absolute"</b></font> <br /><font color="#ffffff">    </font><font color="#000000">width=</font><font color="#990000"><b>"349" </b></font><font color="#000000">height=</font><font color="#990000"><b>"162"</b></font><font color="#000000">></font> <br /><font color="#ffffff"></font> <br /><font color="#000000"><mx:Script></font> <br /><font color="#ffffff">    </font><font color="#000000"><!</font><font color="#000000">[</font><font color="#000000">CDATA</font><font color="#000000">[</font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>import </b></font><font color="#000000">mx.controls.Label;</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#009900">/* *********************</font> <br /><font color="#ffffff">             </font><font color="#009900">UNDO - REDO LOGIC</font> <br /><font color="#ffffff">           </font><font color="#009900">********************* */</font> <br /><font color="#ffffff">           </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#6699cc"><b>var </b></font><font color="#000000">_history:Array = </font><font color="#000000">[]</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#6699cc"><b>var </b></font><font color="#000000">_index:int = -</font><font color="#000000">1</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#6699cc"><b>var </b></font><font color="#000000">closureFactory:Function = </font><font color="#339966"><b>function</b></font><font color="#000000">(</font><font color="#000000">transform:Function, ...args</font><font color="#000000">)</font><font color="#000000">:Function</font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#6699cc"><b>var </b></font><font color="#000000">closure:Function = </font><font color="#339966"><b>function</b></font><font color="#000000">()</font><font color="#000000">:</font><font color="#0033ff"><b>void </b></font><font color="#000000">{</font> <br /><font color="#ffffff">                </font><font color="#000000">transform.apply</font><font color="#000000">(</font><font color="#0033ff"><b>null</b></font><font color="#000000">, args</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">}</font> <br /><font color="#ffffff">            </font><font color="#0033ff"><b>return </b></font><font color="#000000">closure;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">updateHistory</font><font color="#000000">(</font><font color="#000000">undoTransform:Function, redoTransform:Function</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">_index++;</font> <br /><font color="#ffffff">            </font><font color="#000000">_history.splice</font><font color="#000000">(</font><font color="#000000">_index</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">_history.push</font><font color="#000000">(</font> <br /><font color="#ffffff">                </font><font color="#000000">{</font><font color="#000000">forwardTransfrom:redoTransform, reverseTransform:undoTransform</font><font color="#000000">}</font> <br /><font color="#ffffff">            </font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">undo</font><font color="#000000">()</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#0033ff"><b>if </b></font><font color="#000000">(</font><font color="#000000">_index >= </font><font color="#000000">0</font><font color="#000000">) {</font> <br /><font color="#ffffff">                </font><font color="#6699cc"><b>var </b></font><font color="#000000">closure:Function = _history</font><font color="#000000">[</font><font color="#000000">_index</font><font color="#000000">]</font><font color="#000000">.reverseTransform;</font> <br /><font color="#ffffff">                </font><font color="#000000">_index--;</font> <br /><font color="#ffffff">                </font><font color="#000000">closure</font><font color="#000000">()</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">}    </font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">redo</font><font color="#000000">()</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#0033ff"><b>if </b></font><font color="#000000">(</font><font color="#000000">_index < _history.length - </font><font color="#000000">1</font><font color="#000000">) {</font> <br /><font color="#ffffff">                </font><font color="#000000">_index++;</font> <br /><font color="#ffffff">                </font><font color="#6699cc"><b>var </b></font><font color="#000000">closure:Function = _history</font><font color="#000000">[</font><font color="#000000">_index</font><font color="#000000">]</font><font color="#000000">.forwardTransfrom;</font> <br /><font color="#ffffff">                </font><font color="#000000">closure</font><font color="#000000">()</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#009900">/* *********************</font> <br /><font color="#ffffff">             </font><font color="#009900">APPLICATION LOGIC</font> <br /><font color="#ffffff">           </font><font color="#009900">********************* */</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">moveLabel</font><font color="#000000">(</font><font color="#000000">label:Label, dx:Number, dy:Number</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">label.x += dx;</font> <br /><font color="#ffffff">            </font><font color="#000000">label.y += dy;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">moveLogic</font><font color="#000000">(</font><font color="#000000">dx:Number, dy:Number</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#0033ff"><b>if </b></font><font color="#000000">(</font><font color="#000000">myLabel.x + dx < </font><font color="#000000">0</font><font color="#000000">) </font><font color="#0033ff"><b>return</b></font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#0033ff"><b>if </b></font><font color="#000000">(</font><font color="#000000">myLabel.y + dy < </font><font color="#000000">0</font><font color="#000000">) </font><font color="#0033ff"><b>return</b></font><font color="#000000">;</font> <br /><font color="#ffffff">            </font> <br /><font color="#ffffff">            </font><font color="#6699cc"><b>var </b></font><font color="#000000">undo:Function = closureFactory</font><font color="#000000">(</font><font color="#000000">moveLabel, myLabel, -dx, -dy</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#6699cc"><b>var </b></font><font color="#000000">redo:Function = closureFactory</font><font color="#000000">(</font><font color="#000000">moveLabel, myLabel, dx, dy</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">updateHistory</font><font color="#000000">(</font><font color="#000000">undo, redo</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">            </font><font color="#000000">redo</font><font color="#000000">()</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">upHandler</font><font color="#000000">(</font><font color="#000000">e:Event</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">moveLogic</font><font color="#000000">(</font><font color="#000000">0</font><font color="#000000">, -</font><font color="#000000">10</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">downHandler</font><font color="#000000">(</font><font color="#000000">e:Event</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">moveLogic</font><font color="#000000">(</font><font color="#000000">0</font><font color="#000000">, </font><font color="#000000">10</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">leftHandler</font><font color="#000000">(</font><font color="#000000">e:Event</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">moveLogic</font><font color="#000000">(</font><font color="#000000">-</font><font color="#000000">10</font><font color="#000000">, </font><font color="#000000">0</font><font color="#000000">)</font><font color="#000000">;    </font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">        </font> <br /><font color="#ffffff">        </font><font color="#0033ff"><b>private </b></font><font color="#339966"><b>function </b></font><font color="#000000">rightHandler</font><font color="#000000">(</font><font color="#000000">e:Event</font><font color="#000000">)</font><font color="#000000">:</font><font color="#0033ff"><b>void</b></font> <br /><font color="#ffffff">        </font><font color="#000000">{</font> <br /><font color="#ffffff">            </font><font color="#000000">moveLogic</font><font color="#000000">(</font><font color="#000000">10</font><font color="#000000">, </font><font color="#000000">0</font><font color="#000000">)</font><font color="#000000">;</font> <br /><font color="#ffffff">        </font><font color="#000000">}</font> <br /><font color="#ffffff">    </font><font color="#000000">]]</font><font color="#000000">></font> <br /><font color="#000000"></mx:Script></font> <br /><font color="#ffffff"></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Canvas x=</font><font color="#990000"><b>"73" </b></font><font color="#000000">y=</font><font color="#990000"><b>"10" </b></font><font color="#000000">width=</font><font color="#990000"><b>"200" </b></font><font color="#000000">height=</font><font color="#990000"><b>"139" </b></font><font color="#000000">backgroundColor=</font><font color="#990000"><b>"#87FBFF"</b></font><font color="#000000">></font> <br /><font color="#ffffff">        </font><font color="#000000"><mx:Label id=</font><font color="#990000"><b>"myLabel" </b></font><font color="#000000">x=</font><font color="#990000"><b>"51" </b></font><font color="#000000">y=</font><font color="#990000"><b>"53" </b></font><font color="#000000">text=</font><font color="#990000"><b>"move me" </b></font><font color="#000000">fontSize=</font><font color="#990000"><b>"20"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"></mx:Canvas></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"10" </b></font><font color="#000000">y=</font><font color="#990000"><b>"54" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Undo" </b></font><font color="#000000">click=</font><font color="#990000"><b>"undo()"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"10" </b></font><font color="#000000">y=</font><font color="#990000"><b>"84" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Redo" </b></font><font color="#000000">click=</font><font color="#990000"><b>"redo()"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"281" </b></font><font color="#000000">y=</font><font color="#990000"><b>"24" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Up" </b></font><font color="#000000">width=</font><font color="#990000"><b>"58" </b></font><font color="#000000">click=</font><font color="#990000"><b>"upHandler(event)"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"281" </b></font><font color="#000000">y=</font><font color="#990000"><b>"54" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Down" </b></font><font color="#000000">width=</font><font color="#990000"><b>"58" </b></font><font color="#000000">click=</font><font color="#990000"><b>"downHandler(event)"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"281" </b></font><font color="#000000">y=</font><font color="#990000"><b>"84" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Left" </b></font><font color="#000000">width=</font><font color="#990000"><b>"58" </b></font><font color="#000000">click=</font><font color="#990000"><b>"leftHandler(event)"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">    </font><font color="#000000"><mx:Button x=</font><font color="#990000"><b>"281" </b></font><font color="#000000">y=</font><font color="#990000"><b>"114" </b></font><font color="#000000">label=</font><font color="#990000"><b>"Right" </b></font><font color="#000000">width=</font><font color="#990000"><b>"58" </b></font><font color="#000000">click=</font><font color="#990000"><b>"rightHandler(event)"</b></font><font color="#000000">/></font> <br /><font color="#ffffff">        </font> <br /><font color="#000000"></mx:Application></font></code> </td> </tr> </tbody></table> </div> <p align="justify">The array <em>_history</em> holds the undo/redo history, and <em>_index</em> points to the most recent undo or redo operation that has been executed. The function <em>closureFactory</em> takes a generic function along with its arguments then returns a closure. This function is used in application logic (<em>moveLogic</em>) to create the two undo and redo closures and to save them into <em>_history</em> using the function <em>_updateHistory</em>. In <em>closureFactory</em>, I have used <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/Function.html#call()"><em>apply</em></a> to pass a variable number of arguments into <em>transforms’</em> argument list.</p> <p align="justify">Note that <strong><em>only</em></strong> when the label is actually entitled to move, _<em>history</em> is updated with a new closure. Otherwise we would end up with a lot of dummy do-nothing undo/redo actions!</p> <p align="justify">Comments, questions and suggestions are welcomed,</p> </span> Rabih Kodeihhttp://www.blogger.com/profile/16576945032271430312noreply@blogger.com0tag:blogger.com,1999:blog-2999879259919909956.post-72934274602695634652009-08-12T15:57:00.002+03:002009-12-03T16:52:29.848+02:00FINQ: A ‘LINQ to Objects’ implementation in Actionscript 3<p align="justify"><span style="font-size: 85%"><a href="http://msdn.microsoft.com/en-us/netframework/aa904594.aspx" target="_blank">LINQ</a> is a technology which enables developers to efficiently write queries against ubiquitous data sources in a SQL-like declarative style. It’s an impressive technology, especially to developers who aren’t acquainted with <a href="http://www.defmacro.org/ramblings/fp.html" target="_blank">functional programming</a> techniques. Wouldn’t it be nice to have something like LINQ implemented in Actionscript 3? <br /> <br />At first, I started experimenting a bit with “select” and “where” statements, then “join” and “groupBy” and not before long, <span xmlns="xmlns"><span style="font-size: 85%"><a href="http://sites.google.com/site/fileimageserver/files/finq.zip?attredirects=0"><em>FINQ</em></a> was born.</span></span></span></p> <h4 align="justify">What is FINQ and how to use it?</h4> <p align="justify"></p> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">FINQ (<strong>F</strong>lex <strong>In</strong>tegrated <strong>Q</strong>uery) is an implementation of LINQ to Objects <span xmlns="xmlns"><span style="font-size: 85%">(LINQ is basically made up of </span></span><span xmlns="xmlns"><span style="font-size: 85%"><a href="http://msdn.microsoft.com/en-us/library/bb397919.aspx" target="_blank">LINQ to Objects</a> and <a href="http://msdn.microsoft.com/en-us/library/bb386976.aspx" target="_blank">LINQ to SQL</a>)</span></span>. It is entirely written in AS3 and as such can be very easily integrated with any Flex or Flash program. Download the source code <a href="http://sites.google.com/site/fileimageserver/files/finq.zip?attredirects=0">here</a>. To use FINQ in your code or Flex project, just unpack the downloaded file and place the ‘finq’ folder inside the ‘src’ folder of your project then simply import the ‘finq’ package in your code.</span></span></p> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">As an example of how FINQ code looks like, consider the following example which outputs the number of occurrences for each element in a collection of integers: </span></span></p> <div class="snippet" align="justify"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">data:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([</span><span style="color: #000000">1 </span><span style="color: #000000">, </span><span style="color: #000000">1 </span><span style="color: #000000">, </span><span style="color: #000000">1 </span><span style="color: #000000">, </span><span style="color: #000000">2 </span><span style="color: #000000">, </span><span style="color: #000000">2 </span><span style="color: #000000">, </span><span style="color: #000000">2 </span><span style="color: #000000">, </span><span style="color: #000000">3 </span><span style="color: #000000">, </span><span style="color: #000000">3 </span><span style="color: #000000">, </span><span style="color: #000000">4 </span><span style="color: #000000">, </span><span style="color: #000000">4 </span><span style="color: #000000">, </span><span style="color: #000000">4</span><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.groupBy</span><span style="color: #000000">(</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function </b></span><span style="color: #000000">(</span><span style="color: #000000">key</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">key; </span><span style="color: #000000">}</span><span style="color: #000000">, </span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function </b></span><span style="color: #000000">(</span><span style="color: #000000">value</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">1</span><span style="color: #000000">; </span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function </b></span><span style="color: #000000">(</span><span style="color: #000000">key, result</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">{ </span><span style="color: #000000">number:key, count:result.count</span><span style="color: #000000">() }</span><span style="color: #000000">; </span><span style="color: #000000">}</span> <br /><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">([</span><span style="color: #990000"><b>"number"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"count"</b></span><span style="color: #000000">])</span><span style="color: #000000">;</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">Later in this post we will come across a tutorial showing numerous code examples.</span></span></p> <span class="fullpost"> <h4 align="justify">How was FINQ implemented?</h4> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">Truth be told, when I finished writing the code I realized that it was really mostly <a href="http://jacobian.org/writing/syntactic-sugar/" target="_blank">syntactic sugar</a> on top of AS3’s arrays. AS3 is a powerful language, it supports <a href="http://en.allexperts.com/e/c/cl/closure_(computer_science).htm" target="_blank">lexical closures</a>, OOP constructs, <a href="http://en.wikipedia.org/wiki/Dynamic_programming_language" target="_blank">dynamic programming</a>, <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=10_Lists_of_data_4.html" target="_blank">associative arrays</a> and <a href="http://www.webreference.com/programming/javascript/prototypal_inheritance/" target="_blank">prototypal inheritance</a> all in one place! These things make writing the implementation a relatively straightforward task. Most of the functions found in FINQ where implemented using more or less AS3’s built in <a href="http://www.artima.com/weblogs/viewpost.jsp?thread=230610" target="_blank">collections and functional support</a>. I will hopefully try in future posts to elaborate more on this topic. </span></span></p> <h4 align="justify">How is FINQ designed and organized?</h4> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">The design is very simple. It consists of one interface: <em>IEnumerable</em> and one class: <em>FinqObj</em>. <em>IEnumerable</em> defines all the extension methods that normally ship with LINQ plus some few others of my own to mimic the versatility of AS3’s arrays. <em>FinqObj </em>is a class which extends AS3’s <em>Array</em> class and implements <em>IEnumerable</em>. The new method definitions added to <em>IEnumerable</em> are:</span></span></p> <ul> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">forEach</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">getElementKeys</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">getElementKeysDescending</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">nonPrimitives</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">pop</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">primitives</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">print</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">push</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">toArrayCollection</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">toFinqObj </span></span></div> </li> </ul> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">All <em>IEnumerable</em> method definitions were implemented except for the following:</span></span></p> <ul> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">asQueryable</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">longCount</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">toList</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">toLookup</span></span></div> </li> <li> <div align="justify"><span xmlns="xmlns"><span style="font-size: 85%">selectMany</span></span></div> </li> </ul> <p align="justify"><span style="font-size: 85%">It is worth noting that I could have added the extension methods using <em>Array</em>’s prototype object but chose not to because Flex builder 3’s IntelliSense doesn’t know as yet what to do with them, besides I wanted to explicitly introduce the <em>IEnumerable</em> interface.</span></p> <h4 align="justify">So why didn’t I do a ‘FINQ to SQL’?</h4> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">Well, after digging a bit into the inner workings of LINQ, I discovered that LINQ to SQL could not work without so called <a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx" target="_blank">expression trees</a>. In a .NET language complier, when LINQ query code is parsed, it is converted into an intermediate form known as an expression tree. At run time, when the query is about to execute, its corresponding expression tree is used to construct the SQL query string that is passed to the backing database engine for execution. Thus in order to emulate LINQ to SQL, we have to at least provide some sort of mechanism to parse FINQ queries into expression trees. That seems to be a lot of work. <br /> <br />This might be done in Flex builder 3. The idea is to run some kind of a script or a program (possibly written in Java) prior to compiling the AS3 source code, which generates a text file (in a pre-build step), and save the file into the source code project folder. </span></span><span xmlns="xmlns"><span style="font-size: 85%">This file would contain all the textual code definitions of all the FINQ queries that are found in the source during the pre-build step (<span xmlns="xmlns"><span style="font-size: 85%">the </span></span><span xmlns="xmlns"><span style="font-size: 85%">file itself can be deployed as an asset in the complied swf file</span></span>). At runtime, before a certain FINQ query is executed, its related code text is read from the embedded text file and then parsed whereby the expression tree is generated. To perform this last step, we could use something like <a href="http://www.mozilla.org/projects/tamarin/" target="_blank">tamarin</a> or this cool <a href="http://eval.hurlant.com/" target="_blank">AS3 eval complier</a>. </span></span><span xmlns="xmlns"><span style="font-size: 85%">I am not sure if there is a better idea, but this seems to be at least doable. <br /></span></span></p> <h3></h3> <h3>FINQ tutorial</h3> <p align="justify"><span xmlns="xmlns"><span style="font-size: 85%">Let’s start by defining our <em>IEnumerable</em> collection object <em>FinqObj</em>, and adding some <em>elements</em> to it: </span></span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">data:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.push</span><span style="color: #000000">(</span><span style="color: #990000"><b>"orange"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.push</span><span style="color: #000000">(</span><span style="color: #990000"><b>"banana"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.push</span><span style="color: #000000">(</span><span style="color: #990000"><b>"apple"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.push</span><span style="color: #000000">(</span><span style="color: #990000"><b>"grapes"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #000000">data.push</span><span style="color: #000000">(</span><span style="color: #990000"><b>"mango"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Alternatively, we can write:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">data:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([</span><span style="color: #990000"><b>"orange"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"banana"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"apple"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"grapes"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"mango"</b></span><span style="color: #000000">])</span><span style="color: #000000">;</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">To access the stored items, we can simply iterate through <em>data</em> as if it were a normal AS3 array:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #0033ff"><b>for </b></span><code><span style="color: #0033ff"><b><code><span style="color: #0033ff"><b>each </b></span></code></b></span></code><span style="color: #000000">(</span><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">e:String in data</span><span style="color: #000000">) {</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">(</span><span style="color: #000000">e</span><span style="color: #000000">)</span> <br /><span style="color: #000000">}</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// orange</span> <br /><span style="color: #009900">// banana</span> <br /><span style="color: #009900">// apple</span> <br /><span style="color: #009900">// grapes</span> <br /><span style="color: #009900">// mango</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">A little handy function is <em>print()</em> which returns a string output of the data and also prints the data on the Flex builder debug console:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">data.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// orange</span> <br /><span style="color: #009900">// banana</span> <br /><span style="color: #009900">// apple</span> <br /><span style="color: #009900">// grapes</span> <br /><span style="color: #009900">// mango</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Let’s now perform some transformations on <em>data </em>using <em>select()</em>:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">data.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">x.length; </span><span style="color: #000000">})</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// 6</span> <br /><span style="color: #009900">// 6</span> <br /><span style="color: #009900">// 5</span> <br /><span style="color: #009900">// 6</span> <br /><span style="color: #009900">// 5</span> <br /><span style="color: #ffffff"></span> <br /><span style="color: #000000">data.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">{ </span><span style="color: #000000">type:x, length:x.length </span><span style="color: #000000">}</span><span style="color: #000000">; </span><span style="color: #000000">})</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// length:6 type:orange </span> <br /><span style="color: #009900">// length:6 type:banana </span> <br /><span style="color: #009900">// length:5 type:apple </span> <br /><span style="color: #009900">// length:6 type:grapes </span> <br /><span style="color: #009900">// length:5 type:mango</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">In both cases, the select statement applies the inner anonymous function (referred to as <em>closure</em> from now on) to every element of <em>data</em> resulting in a new <em>IEnumerable </em>collection. In each closure above, the variable <em>x</em> represents an individual element of <em>data</em>. Most FINQ functions (at least those who return <em>IEnumerable</em>) are non-destructive to the original data meaning that the output is a completely new object. </span></p> <p align="justify"><span style="font-size: 85%">The output of the second select statement is a bit odd, <em>length</em> was printed before <em>type</em>, this is because the order of <key, value> pairs is not guaranteed in AS3 objects and associative arrays. To straighten this out, we could use:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">data.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">{ </span><span style="color: #000000">type:x, length:x.length </span><span style="color: #000000">}</span><span style="color: #000000">; </span><span style="color: #000000">})</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.print</span><span style="color: #000000">([</span><span style="color: #990000"><b>"type"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"length"</b></span><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// type:orange length:6 </span> <br /><span style="color: #009900">// type:banana length:6 </span> <br /><span style="color: #009900">// type:apple length:5 </span> <br /><span style="color: #009900">// type:grapes length:6 </span> <br /><span style="color: #009900">// type:mango length:5</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">A nice feature of <em>select()</em> is that you can get any <key, value> pair in the element object using a notation similar to the above <em>print()</em> statement:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">people:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">name:</span><span style="color: #990000"><b>"Allen Frances"</b></span><span style="color: #000000">, age:</span><span style="color: #000000">11</span><span style="color: #000000">, canCode:</span><span style="color: #0033ff"><b>false</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">name:</span><span style="color: #990000"><b>"Burke Madison"</b></span><span style="color: #000000">, age:</span><span style="color: #000000">50</span><span style="color: #000000">, canCode:</span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">}</span><span style="color: #000000">, </span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">name:</span><span style="color: #990000"><b>"David Charles"</b></span><span style="color: #000000">, age:</span><span style="color: #000000">33</span><span style="color: #000000">, canCode:</span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">name:</span><span style="color: #990000"><b>"Connor Morgan"</b></span><span style="color: #000000">, age:</span><span style="color: #000000">50</span><span style="color: #000000">, canCode:</span><span style="color: #0033ff"><b>false</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">name:</span><span style="color: #990000"><b>"Everett Frank"</b></span><span style="color: #000000">, age:</span><span style="color: #000000">16</span><span style="color: #000000">, canCode:</span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #000000">people.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"canCode"</b></span><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">//people.where(function(</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// canCode:false name:Allen Frances </span> <br /><span style="color: #009900">// canCode:true name:Burke Madison </span> <br /><span style="color: #009900">// canCode:true name:David Charles </span> <br /><span style="color: #009900">// canCode:false name:Connor Morgan </span> <br /><span style="color: #009900">// canCode:true name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">which is also equivalent to:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">{ </span><span style="color: #000000">name:x.name, canCode:x.canCode </span><span style="color: #000000">}</span><span style="color: #000000">; </span><span style="color: #000000">})</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// canCode:false name:Allen Frances </span> <br /><span style="color: #009900">// canCode:true name:Burke Madison </span> <br /><span style="color: #009900">// canCode:true name:David Charles </span> <br /><span style="color: #009900">// canCode:false name:Connor Morgan </span> <br /><span style="color: #009900">// canCode:true name:Everett Frank </span></code></td> </tr> </tbody></table> </div> <span style="font-size: 85%"></span> <p align="justify"><span style="font-size: 85%">You can also retrieve an array of keys for collections containing elements which are either <em>Array</em>s or <em>Object</em>s, and iterate through it</span><span style="font-size: 85%">: </span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">result:IEnumerable = data.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">{ </span><span style="color: #000000">type:x, length:x.length </span><span style="color: #000000">}</span><span style="color: #000000">; </span><span style="color: #000000">})</span><span style="color: #000000">;</span> <br /><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">keys:Array = result.getElementKeys</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #0033ff"><b>for </b></span><code><span style="color: #0033ff"><b><code><span style="color: #0033ff"><b>each </b></span></code></b></span></code><span style="color: #000000">(</span><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">key:String in keys</span><span style="color: #000000">) {</span> <br /><span style="color: #ffffff"></span><span style="color: #6699cc"><b>   var </b></span><span style="color: #000000">element:Object = result</span><span style="color: #000000">[</span><span style="color: #000000">0</span><span style="color: #000000">]</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">(</span><span style="color: #000000">element</span><span style="color: #000000">[</span><span style="color: #000000">key</span><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #000000">}</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// 6 </span> <br /><span style="color: #009900">// orange</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Suppose now we want to find out who can code among <em>people</em>:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.where</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">x.canCode == </span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">; </span><span style="color: #000000">})</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// age:50 canCode:true name:Burke Madison </span> <br /><span style="color: #009900">// age:33 canCode:true name:David Charles </span> <br /><span style="color: #009900">// age:16 canCode:true name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%"></span></p> <p align="justify"><span style="font-size: 85%">Just like <em>select()</em>, <em>where()</em> also returns an <em>IEnumerable</em> collection. In general, all the functions with a return value type of <em>IEnumerable</em> can be chained together to construct more sophisticated queries:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.where</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">x.canCode == </span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">; </span><span style="color: #000000">})</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">) </span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// name:Burke Madison </span> <br /><span style="color: #009900">// name:David Charles </span> <br /><span style="color: #009900">// name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Sometimes it is useful to defer the execution of a query. This can be easily achieved by wrapping the query with a closure as shown in the following snippet:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #009900">// query defined here: </span> <br /><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">whoCanCode = </span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">data:IEnumerable</span><span style="color: #000000">) {</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>   return </b></span><span style="color: #339966"><b>function</b></span><span style="color: #000000">() {</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      return </b></span><span style="color: #000000">data.where</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">x.canCode == </span><span style="color: #0033ff"><b>true</b></span><span style="color: #000000">; </span><span style="color: #000000">})</span><span style="color: #000000">.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">)</span><span style="color: #000000">; </span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   } </span> <br /><span style="color: #000000">})(</span><span style="color: #000000">people</span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #009900">//. </span> <br /><span style="color: #009900">//.</span> <br /><span style="color: #009900">// the original data source is assigned a new value here:</span> <br /><span style="color: #000000">people = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([</span><span style="color: #000000">1 </span><span style="color: #000000">,</span><span style="color: #000000">2 </span><span style="color: #000000">,</span><span style="color: #000000">3</span><span style="color: #000000">])</span><span style="color: #000000">;;</span> <br /><span style="color: #009900">//. </span> <br /><span style="color: #009900">//. </span> <br /><span style="color: #009900">// query executed here: </span> <br /><span style="color: #000000">whoCanCode</span><span style="color: #000000">()</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">; </span> <br /><span style="color: #009900">// OUTPUTS: </span> <br /><span style="color: #009900">// name:Burke Madison </span> <br /><span style="color: #009900">// name:David Charles </span> <br /><span style="color: #009900">// name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"></p> <p align="justify"><span style="font-size: 85%"></span></p> <span style="font-size: 85%">So far so good.</span> <p></p> <p align="justify"><span style="font-size: 85%">But before we proceed any further, I want to introduce a useful little naming convention regarding argument closures. If you look at the method signatures in <em>IEnumerable</em>, you will notice that most closure argument names end with one of the following strings:</span></p> <ul> <li> <div align="justify"><span style="font-size: 85%"><em>selector</em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>aggregator</em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>comparer</em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>equlalityComparer</em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>predicate</em></span></div> </li> </ul> <p align="justify"><span style="font-size: 85%">The convention is that those closures are considered to have types according to:</span></p> <table border="0" cellspacing="0" cellpadding="2" width="458"><tbody> <tr> <td valign="top" width="147"> <ul> <li> <div align="justify"><span style="font-size: 85%"><em>selector </em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>aggregator </em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>comparer </em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>equlalityComparer </em></span></div> </li> <li> <div align="justify"><span style="font-size: 85%"><em>predicate</em> </span></div> </li> </ul> </td> <td valign="top" width="113"> <p align="justify"><span style="font-size: 85%">= function (x)</span> <br /><span style="font-size: 85%">= function (x, y) <br /></span><span style="font-size: 85%">= function (x, y) </span> <br /><span style="font-size: 85%">= function (x, y) <br /></span><span style="font-size: 85%">= function (x) </span></p> </td> <td valign="top" width="196"> <p align="justify"><span style="font-size: 85%">returns <strong>dynamic</strong> <strong>type</strong></span><strong> </strong> <br /><span style="font-size: 85%">returns </span><span style="font-size: 85%"><strong>dynamic</strong> <strong>type</strong></span> <span style="font-size: 85%"> <br /></span><span style="font-size: 85%">returns <strong>int</strong> within {-1, 0, +1}</span> <br /><span style="font-size: 85%">returns <strong>Boolean</strong> <br /></span><span style="font-size: 85%">returns <strong>Boolean</strong></span> </p> </td> </tr> </tbody></table> <p align="justify"><span style="font-size: 85%">For example, the <em>orderBy()</em> function takes a <em>keySelector</em> and an optional <em>keyComparer</em>. The <em>keySelector</em> specifies which key the ordering should be done relative to and the <em>keyComparer</em> specifies how two keys should be compared relative to each other. According to our naming convention, <em>keySelector</em>’s name ends with “selector” and therefore it is a function which takes one argument (of any type) and returns a <a href="http://books.google.com.lb/books?id=6uhORLiHHiwC&pg=PA17&lpg=PA17&dq=dynamic+type+asterisk+actionscript+3&source=bl&ots=P_99RpfuXS&sig=yPjC7eXsPXXgbZCQwV5XS518euY&hl=en&ei=FX6FSqrPO9eO_AaQiKi9Bw&sa=X&oi=book_result&ct=result&resnum=1#v=onepage&q=&f=false" target="_blank">dynamic type</a> (in the example below, it returns a <em>String</em>). Likewise, <em>keyComparer</em>’s name ends with “comparer” and as such it is a function which takes two arguments (also of any type) and returns an integer. Checkout the following example for an illustration:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.orderBy</span><span style="color: #000000">(</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">x.name; </span><span style="color: #000000">}</span><span style="color: #000000">, <code><span style="color: #009900">// keySelector</span></code> </span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function</b></span><span style="color: #000000">(</span><span style="color: #000000">x:String, y:String</span><span style="color: #000000">) { <code><span style="color: #000000"><code><span style="color: #009900">// keyComparer</span></code></span> </code></span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      if </b></span><span style="color: #000000">(</span><span style="color: #000000">x.toUpperCase</span><span style="color: #000000">() </span><span style="color: #000000">> y.toUpperCase</span><span style="color: #000000">()) </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">+</span><span style="color: #000000">1</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      if </b></span><span style="color: #000000">(</span><span style="color: #000000">x.toUpperCase</span><span style="color: #000000">() </span><span style="color: #000000">== y.toUpperCase</span><span style="color: #000000">()) </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">0</span><span style="color: #000000">; </span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      return </b></span><span style="color: #000000">-</span><span style="color: #000000">1</span><span style="color: #000000">; </span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   } <br /></span><span style="color: #000000">)</span><span style="color: #000000">.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// name:Allen Frances </span> <br /><span style="color: #009900">// name:Burke Madison </span> <br /><span style="color: #009900">// name:Connor Morgan </span> <br /><span style="color: #009900">// name:David Charles </span> <br /><span style="color: #009900">// name:Everett Frank</span></code> </td> </tr> <tr> <td valign="top" align="left"> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">To be more concise, I will refer from now on to closure types by their ending string (a <em>keySelector</em> is a selector, a <em>keyComparer</em> is a comparer, etc…).</span></p> <p align="justify"><span style="font-size: 85%">If you look more closely at the signature of <em>orderBy()</em>, you’ll notice oddly that it specifies <em>keySelector</em> as a dynamic type (indicated by using a wildcard) instead of a Function. When a wildcard is used to specify the argument type, it means that the argument can be either a closure or a string specifying the the element key.</span></p> <p align="justify"><span style="font-size: 85%">A</span><span style="font-size: 85%"> comparer usually returns and integer value of –1, 0 or +1 but it is annoying to write tests (as in the above code) each time we want to supply a comparer. That’s why I’ve introduced the option of a comparer returning a boolean (ex: return { x < y; }), the <em>FinqObj</em> implementation is smart enough to interpret the difference. Thus our previous <em>orderBy</em>() example can been written more succinctly as follows:</span></p> <p align="justify"><span style="font-size: 85%"></span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.orderBy</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">, </span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">x, y</span><span style="color: #000000">) { </span><span style="color: #0033ff"><b>return </b></span><span style="color: #000000">(</span><span style="color: #000000">x.toUpperCase</span><span style="color: #000000">() </span><span style="color: #000000">> y.toUpperCase</span><span style="color: #000000">())</span><span style="color: #000000">; </span><span style="color: #000000">})</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// name:Allen Frances </span> <br /><span style="color: #009900">// name:Burke Madison </span> <br /><span style="color: #009900">// name:Connor Morgan </span> <br /><span style="color: #009900">// name:David Charles </span> <br /><span style="color: #009900">// name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Just like in a phone book, we can nest ordering operations using <em>thenBy()</em>:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">people.orderBy</span><span style="color: #000000">(</span><span style="color: #990000"><b>"canCode"</b></span><span style="color: #000000">)</span><span style="color: #000000">.thenBy</span><span style="color: #000000">(</span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">)</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">.select</span><span style="color: #000000">(</span><span style="color: #990000"><b>"canCode"</b></span><span style="color: #000000">, </span><span style="color: #990000"><b>"name"</b></span><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// canCode:false name:Allen Frances </span> <br /><span style="color: #009900">// canCode:false name:Connor Morgan </span> <br /><span style="color: #009900">// canCode:true name:Burke Madison </span> <br /><span style="color: #009900">// canCode:true name:David Charles </span> <br /><span style="color: #009900">// canCode:true name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">One of the most powerful commands in FINQ is <em>groupBy()</em>. Say we want to group <em>people</em> in two separate lists according to who can and who can’t code:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">result:IEnumerable = people.groupBy</span><span style="color: #000000">(</span><span style="color: #990000"><b>"canCode"</b></span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #0033ff"><b>for </b></span><code><span style="color: #0033ff"><b><code><span style="color: #0033ff"><b>each </b></span></code></b></span></code><span style="color: #000000">(</span><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">element:* in result</span><span style="color: #000000">) {</span> <br /><span style="color: #ffffff"></span><span style="color: #6699cc"><b>   var </b></span><span style="color: #000000">key:String = element.key;</span> <br /><span style="color: #ffffff"></span><span style="color: #6699cc"><b>   var </b></span><span style="color: #000000">group:IEnumerable = element.value;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">(</span><span style="color: #990000"><b>"canCode : " </b></span><span style="color: #000000">+ key</span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   group.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #000000">} </span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// canCode : false</span> <br /><span style="color: #009900">// age:11 canCode:false name:Allen Frances </span> <br /><span style="color: #009900">// age:50 canCode:false name:Connor Morgan </span> <br /><span style="color: #009900">//</span> <br /><span style="color: #009900">// canCode : true</span> <br /><span style="color: #009900">// age:50 canCode:true name:Burke Madison </span> <br /><span style="color: #009900">// age:33 canCode:true name:David Charles </span> <br /><span style="color: #009900">// age:16 canCode:true name:Everett Frank</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">When the query is executed, <em>groupBy</em>() applies its input <em>keySelector</em> argument to every element in <em>people</em> and creates a <key, value> pair accordingly. The key part in the pair holds the result of <em>keySelector</em> and the value part of the pair holds an <em>IEnumerable</em> list of elements having all the same key as computed by <em>keySelector</em> for that pair.</span></p> <p align="justify"><span style="font-size: 85%"><em>groupBy()</em> is a peculiar command, it can be used to implement complicated queries. For example, suppose we need the names of <em>people</em> sorted in three distinct age groups:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">result:IEnumerable = people.groupBy</span><span style="color: #000000">(</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function</b></span><span style="color: #000000">(</span><span style="color: #000000">x</span><span style="color: #000000">) { </span><span style="color: #009900">// keySelector</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      if </b></span><span style="color: #000000">( </span><span style="color: #000000">x.age > </span><span style="color: #000000">0 </span><span style="color: #000000">&& x.age <= </span><span style="color: #000000">20 </span><span style="color: #000000">) </span><span style="color: #0033ff"><b>return </b></span><span style="color: #990000"><b>"adolescent"</b></span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      if </b></span><span style="color: #000000">( </span><span style="color: #000000">x.age > </span><span style="color: #000000">20 </span><span style="color: #000000">&& x.age <= </span><span style="color: #000000">35 </span><span style="color: #000000">) </span><span style="color: #0033ff"><b>return </b></span><span style="color: #990000"><b>"young"</b></span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      if </b></span><span style="color: #000000">( </span><span style="color: #000000">x.age > </span><span style="color: #000000">35 </span><span style="color: #000000">) </span><span style="color: #0033ff"><b>return </b></span><span style="color: #990000"><b>"veteran"</b></span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   }</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #990000"><b>   "name" </b></span><span style="color: #009900">// elementSelector</span> <br /><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #0033ff"><b>for <code><span style="color: #0033ff"><b>each </b></span></code></b></span><span style="color: #000000">(</span><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">element:* in result</span><span style="color: #000000">) {</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">(</span><span style="color: #990000"><b>"Age group : " </b></span><span style="color: #000000">+ element.key</span><span style="color: #000000">)</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   (</span><span style="color: #000000">element.value </span><span style="color: #0033ff"><b>as </b></span><span style="color: #000000">IEnumerable</span><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   trace</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #000000">} </span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// Age group : adolescent</span> <br /><span style="color: #009900">// Allen Frances</span> <br /><span style="color: #009900">// Everett Frank</span> <br /><span style="color: #009900">// </span> <br /><span style="color: #009900">// Age group : veteran</span> <br /><span style="color: #009900">// Burke Madison</span> <br /><span style="color: #009900">// Connor Morgan</span> <br /><span style="color: #009900">// </span> <br /><span style="color: #009900">// Age group : young</span> <br /><span style="color: #009900">// David Charles</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">Here we have used an <em>elementSelector</em> as well. When the list of results is constructed for each key, <em>elementSelector</em> is applied to every element (that matches the key) prior to its addition to the list. </span></p> <p align="justify"><span style="font-size: 85%">Now we come to the venerable <em>join()</em>. Consider the classical example of customers and orders:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">customers:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([ </span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">1</span><span style="color: #000000">, name:</span><span style="color: #990000"><b>"Gotts"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">2</span><span style="color: #000000">, name:</span><span style="color: #990000"><b>"Valdes"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">3</span><span style="color: #000000">, name:</span><span style="color: #990000"><b>"Gauwin"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">4</span><span style="color: #000000">, name:</span><span style="color: #990000"><b>"Deane"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">5</span><span style="color: #000000">, name:</span><span style="color: #990000"><b>"Zeeman"</b></span><span style="color: #000000">} </span> <br /><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #6699cc"><b>var </b></span><span style="color: #000000">orders:IEnumerable = </span><span style="color: #0033ff"><b>new </b></span><span style="color: #000000">FinqObj</span><span style="color: #000000">([</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">1</span><span style="color: #000000">, description:</span><span style="color: #990000"><b>"Order 1"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">1</span><span style="color: #000000">, description:</span><span style="color: #990000"><b>"Order 2"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">4</span><span style="color: #000000">, description:</span><span style="color: #990000"><b>"Order 3"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">4</span><span style="color: #000000">, description:</span><span style="color: #990000"><b>"Order 4"</b></span><span style="color: #000000">}</span><span style="color: #000000">,</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   {</span><span style="color: #000000">id:</span><span style="color: #000000">5</span><span style="color: #000000">, description:</span><span style="color: #990000"><b>"Order 5"</b></span><span style="color: #000000">}</span> <br /><span style="color: #000000">])</span><span style="color: #000000">;</span> <br /><span style="color: #000000">customers.join</span><span style="color: #000000">( </span><span style="color: #009900">// outer</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   orders, </span><span style="color: #009900">// inner</span> <br /><span style="color: #ffffff"></span><span style="color: #990000"><b>   "id"</b></span><span style="color: #000000">, </span><span style="color: #009900">// outerKeySelector </span> <br /><span style="color: #ffffff"></span><span style="color: #990000"><b>   "id"</b></span><span style="color: #000000">, </span><span style="color: #009900">// innerKeySelector</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>   function</b></span><span style="color: #000000">(</span><span style="color: #000000">c, o</span><span style="color: #000000">) { </span><span style="color: #009900">// resultAggregator </span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>      return </b></span><span style="color: #000000">{ </span><span style="color: #000000">customerName:c.name, order:o.description </span><span style="color: #000000">}</span><span style="color: #000000">;</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">   }</span> <br /><span style="color: #000000">)</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// customerName:Gotts order:Order 1 </span> <br /><span style="color: #009900">// customerName:Gotts order:Order 2 </span> <br /><span style="color: #009900">// customerName:Deane order:Order 3 </span> <br /><span style="color: #009900">// customerName:Deane order:Order 4 </span> <br /><span style="color: #009900">// customerName:Zeeman order:Order 5</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">This examples deserves some explanation:</span></p> <p align="justify"><span style="font-size: 85%"><em>inner</em> is the <em>IEnumerable</em> collection to join with <em>outer.</em> The two selectors <em>outerKeySelector</em> and <em>innerKeySelector</em> are used to get the corresponding keys from <em>outer</em> and <em>inner</em> to be matched in the join operation. The final aggregator closure <em>resultAggregator</em> is simply applied to each matching element pair (from <em>inner</em> and <em>outer</em>) in order to compute the resulting element.</span></p> <p align="justify"><span style="font-size: 85%">Suppose now we wanted to group our last join result by <em>customerName</em>. We can of course append a simple <em>groupBy()</em> query to <em>join()</em>, but there is shorter way to do it using <em>groupJoin()</em>. The signature of <em>groupJoin()</em> is exactly the same as the signature of <em>join()</em> and operates in almost the same way. The only difference is that instead of joining <em>outer</em> and <em>inner</em> by directly matching keys, first <em>innerKeySelector</em> is used in a <em>groupBy()</em> like operation on <em>inner</em> then the result is matched with <em>outer</em> using <em>outerKeySelector</em><span style="font-size: 85%"></span>. C</span><span style="font-size: 85%">heck out the following code which demonstrates the concept:</span></p> <div class="snippet" align="left"> <table border="0" cellspacing="0" cellpadding="3"><tbody> <tr> <td valign="top" align="left"><code><span style="color: #000000">customers.groupJoin</span><span style="color: #000000">( </span><span style="color: #009900">// outer</span> <br /><span style="color: #ffffff"></span><span style="color: #000000">orders, </span><span style="color: #009900">// inner</span> <br /><span style="color: #ffffff"></span><code><span style="color: #990000"><b>"id"</b></span></code><span style="color: #000000">, </span><span style="color: #009900">// outerKeySelector</span> <br /><span style="color: #ffffff"></span><code><span style="color: #990000"><b>"id"</b></span></code><span style="color: #000000">, </span><span style="color: #009900">// innerKeySelector</span> <br /><span style="color: #ffffff"></span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">c, g</span><span style="color: #000000">) { </span><span style="color: #009900">// resultAggregator</span> <br /><span style="color: #ffffff"></span><span style="color: #0033ff"><b>   return </b></span><span style="color: #000000">{ <br />      c</span><span style="color: #000000">ustomerName:c.name, <br />      orders:g.select</span><span style="color: #000000">(</span><span style="color: #339966"><b>function</b></span><span style="color: #000000">(</span><span style="color: #000000">order</span><span style="color: #000000">) {</span> <span style="color: #0033ff"><b>return </b></span><span style="color: #000000">order.description; </span><span style="color: #000000">}</span><span style="color: #000000">) <br />   }</span><span style="color: #000000">; <br /></span><span style="color: #000000">})</span><span style="color: #000000">.print</span><span style="color: #000000">()</span><span style="color: #000000">;</span> <br /><span style="color: #009900">// OUTPUTS:</span> <br /><span style="color: #009900">// customerName:Gotts orders:Order 1,Order 2 </span> <br /><span style="color: #009900">// customerName:Valdes orders: </span> <br /><span style="color: #009900">// customerName:Gauwin orders: </span> <br /><span style="color: #009900">// customerName:Deane orders:Order 3,Order 4 </span> <br /><span style="color: #009900">// customerName:Zeeman orders:Order 5</span></code> </td> </tr> </tbody></table> </div> <p align="justify"><span style="font-size: 85%">There are still other FINQ functions such as </span><span style="font-size: 85%"><em>union()</em>, <em>intersection()</em>, <em>max()</em>, <em>min()</em> and many more. All of those are fairly similar to their LINQ counterparts and relatively easy to understand.</span></p> <h4>Some caveats</h4> <p align="justify"><span style="font-size: 85%">There are a few things native to LINQ which aren’t easily portable to FINQ: <a href="http://www.developer.com/net/csharp/article.php/3601646" target="_blank">type inference</a> and IntelliSense support (this requires changes at the compiler and IDE levels), <a href="http://msdn.microsoft.com/en-us/library/bb397687.aspx" target="_blank">lambda expressions</a> (admittedly lambda expressions allow more succinct queries but with closures they are not absolutely necessary), and as mentioned at the beginning of this post, <a href="http://msdn.microsoft.com/en-us/library/bb397951.aspx" target="_blank">expression trees</a>.</span> </p> <h4>Conclusion</h4> <p align="justify"><span style="font-size: 85%">I hope you find FINQ useful. You are welcomed to post any comment.</span></p> </span> Rabih Kodeihhttp://www.blogger.com/profile/16576945032271430312noreply@blogger.com6