Monday, September 26, 2005

Comparing C# 3.0 and VB 9.0 LINQ Syntax

Prior to LINQ's introduction, differences between the C# and VB (.NET) languages were almost exclusively syntatical. The .NET Framework's classes and the CLR's MSIL unified the capabilities of programs written with C# and VB. If the release version of Visual Studio "Orcas" includes LINQ and its DLinq and XLinq APIs, much of the everyday data-management and XML-processing syntax of C# 3.0 and VB 9.0 source code will diverge dramatically. .NET developers will need to evaluate the language's query operator set and query effectiveness before deciding between C# 3.0 or VB 9.0 for writing data-intensive .NET 3.0 applications or components.

.NET developers usually base their choice of language on their programming background. As a general rule C/C++/Java programmers, who are likely to have learned these languages while attending a college or university, choose C#. VB (COM) developers, most of whom learned the language by reading books and attending conferences or training classes, adopt VB .NET. The VS team has identified the following three Windows programmer personae:

  • Mort, the opportunistic developer, likes to create quick-working solutions for immediate problems, focuses on productivity, and learns new language skills as needed. Morts commonly create ad hoc, line-of-business applications and components with VB.
  • Elvis, the pragmatic programmer, likes to create long-lasting solutions that address the problem domain, and learns while working on the solution. Elvises commonly use C# to develop reusable components and enjoy implementing advanced .NET features, such as remoting and the Windows Communication Framework (WCF or Indigo).
  • Einstein, the paranoid programmer, likes to create the most efficient solution to a given problem, and typically learn in advance before working on the solution. Einsteins usually have a C/C++ background and a master's degree or higher, and some write Windows device drivers.

The preceding descriptions were adapted from Nikhil Kothari's blog entry. Wesner Moise offers similar descriptions for the three personae, and Rockford Lhotka provides a detailed analysis of Mort as a business programmer.

Microsoft's VB and C# teams diverge on LINQ syntax. VB 9.0 query comprehensions support SQL-like operators, while C# keywords have a decided XQuery FLWOR (for, let, where, order by, return) flavor. (Wes's "LINQ Syntax" item offers a sample FLWOR expression and its C# query counterpart.)

Compare this preliminary list of VB 9.0 query keywords from Paul Vick's PDC 2005 presentation:

  • Project: Select <expr> From <expr> In <expr>
  • Filter: Where <expr>
  • Test: Any(<expr>), All(<expr>)
  • Join: <expr> [[Left Right] Outer] Join <expr> On <expr>
  • Group: Group By <expr>
  • Aggregate: Count(<expr>), Sum(<expr>), Min(<expr>), Max(<expr>), Avg(<expr>)
  • Partition: Top(<expr>);
  • Set: Distinct, Union, Intersect, Except
  • Order: Order By <expr> [[Asc] Desc]

with this much longer list of C# 3.0 query operators from the LINQ Project overview document, which is missing the From and In operators:

  • OfType: Filter based on type affiliation
  • Select/SelectMany: Project based on transform function
  • Where: Filter based on predicate function
  • Count: Count based on optional predicate function
  • All/Any: Universal/Existential quantification based on predicate function
  • First/FirstOrDefault: Access initial member based on optional predicate function
  • ElementAt: Access member at specified position
  • Take/Skip: Access members before/after specified position (paging)
  • TakeWhile/SkipUntil: Access members before/after predicate function is satisfied
  • GroupBy: Partition based on key extraction function
  • ToDictionary: Create key/value dictionary based on key extraction function
  • OrderBy/ThenBy: Sort in ascending order based on key extraction function and optional comparison function
  • OrderByDescending/ThenByDescending: Sort in descending order based on key extraction function and optional comparison function
  • Reverse: Reverse the order of a sequence
  • Fold: Aggregate value over multiple values based on aggregation function
  • Min/Max/Sum/Average: Numeric aggregation functions
  • Distinct: Filter duplicate members
  • Except: Filter elements that are members of specified set
  • Intersect: Filter elements that are not members of specified set
  • Union: Combine distinct members from two sets
  • Concat: Concatenate the values of two sequences
  • ToArray/ToList: Buffer results of query in array or List
  • Range: Create a sequence of numbers in a range
  • Repeat: Create a sequence of multiple copies of a given value

In addition to the query comprehension operator (keyword) differences between VB and C#, C# reverses the sequence of SQL's SELECT and FROM clauses. The following VB expression:

expr = Select s.ToUpper() From s In names Where s.Length = 5 Order By s

translates to this C# expression:

expr = from s in names where s.Length == 5 orderby s select s.ToUpper() ;

Paul Vick addresses the query comprehension operator sequence issue from the VB Team's standpoint—following the SQL convention simplifies usage because VB programmers (Morts) are likely to be conversant with SQL. However, substitution of In for As departs from SQL convention. I would have no problem with either

expr = Select s.ToUpper() From names As s Where s.Length = 5 Order By s


expr = From s In names Where s.Length = 5 Order By s Select s.ToUpper()

but I'd prefer the latter construction if it improved performance, reduced resource consumption, or is the only sequence that would support IntelliSense fully. Implementing IntelliSense for the previous example's Select list appears to me to be impossible in advance of defining the data source with the From ... In clause.

Wesner Moise makes the following observations in his VB 9 item of September 16, 2005:

The difference in focus between the C# and VB team is becoming much more evident: The VB team is opting for greater relevance and convenience in the short term, while the C# team is trying to avoid creating long-term baggage. The end result is that Visual Basic is definitely going to be much more fun to program. [Emphasis added.]

While the C# [team] has decided to include a few choice SQL keywords (select, from, where, orderby and groupby) and no XML literals, the VB team has opted to include the full range of keywords available in a SQL query as well as support for embedded XML with schema validation.

Paul Vick confirms Wes's conclusion from the XLinq perspective in his "Integrating XML: Playing with Fire?" item. However, DLinq users undoubtedly will want to see Having, the In() predicate and other commonly-used ANSI SQL reserved words added to VB's query comprehension operators list.

The upshot: VB 9.0 will be firmly in the Mort camp and C# 3.0 will continue to appeal primarily to the Elvis and Einstein crowd. Whether the two sets of query comprehension operators will have identical capabilities with both the DLinq and XLinq APIs remains to be seen.


Update: 10/11/2005: Interact Software, Ltd's Ian Griffiths explains the significance of and demonstrates C# 3.0 expression trees in his "C# 3.0 and LINQ - Expression Trees" post.



Anonymous said...

Great.. Really Gtreat..
Thanks a lot..