Whidbey and Orcas
Tuesday, October 4, 2005
The next .NET version on the horizon, 3.0 code-named Orcas, is getting a lot of attention already. This article is on the bleeding edge, a work in progress.
Language Features
There are a number of new language features in Orcas. Both C# and VB.NET have many of them in common, while some features are just for one of them.
Feature Roadmap
Since VB.NET catches up on some C# Whidbey goodies, and others are quite important ground work for the new Orcas features, and even Whidbey is kind of new, let's summarize major new language features for both languages introduced in .NET 2.0 and announced for .NET 3.0:
Group | Feature | Description | C# | VB |
---|---|---|---|---|
Declarations | Implicitly Typed Locals | Type inferrence on initialization expression | Orcas | Orcas |
Implicitly Typed Arrays | Type inferrence on array initializer | Orcas | * | |
Initialization | Object Initializers | Assigning to members in creation expression | Orcas | Orcas |
Collection Initializers | Requires ICollection<T>, which declares method Add(T) | Orcas | Orcas | |
Type System | Generics | Runtime parameterized types | Whidbey | Whidbey |
Anonymous Types or Tuples | Ad-hoc compiler-generated class types | Orcas | Orcas | |
Nullable Types | Special compiler support for System.Nullable | Whidbey | Orcas | |
Methods and Delegates | Iterators | Stateful generator functions | Whidbey | - |
Extension Methods | Syntactic sugar for functions | Orcas | Orcas | |
Delegate Relexation | Return type covariance, parameter contravariance | Whidbey | Orcas | |
Closures, Lambdas | Nested Functions | Named local subroutines | Whidbey* | Orcas |
Anonymous Methods | Without names | Whidbey | * | |
Lambdas | Based on delegates | Orcas | * | |
Expression Tress | Lambdas as data structures | Orcas | - | |
Language Integration | Query Expressions | Language-integrated SQL | Orcas | Orcas |
XML Literals | Language-integrated XML | - | Orcas | |
Late Binding | Duck Typing | Dynamic Interfaces | - | Orcas |
Dynamic Identifiers | Like Call-By-Name | - | Orcas |
Lambda Expressions
Given to following declarations/definitions ...
delegate string CharDuplicator(char ch, int count); string DuplicateChar(char ch, int count, CharDuplicator predicate){ return predicate(ch, count); } char ch = '#';
... the method may be called like this in Whidbey ...
string result = DuplicateChar( ch, 5, delegate(char ch, int count){ return new string(ch, count); } );
... which is equivalent to the following Orcas code:
string result = DuplicateChar( ch, 5, (char ch, int count) => {return new string(ch, count);} );
If there is only one statement, the body of the lambda may be an expression instead of a statement block:
(char ch, int count) => new string(ch, count)
The type of the parameters may be inferred from the context - unlike in anonymous methods:
(ch, count) => new string(ch, count)
If there are multiple parameters, as in this case, they need to be enclosed by parens. Otherwise, the following will suffice:
ch => new string(ch, sbyte.MaxValue);
If the delegate specifies no parameters at all, an empty parameter list, is used):
() => new string('#', sbyte.MaxValue);
Additional features are:
- Method group conversions: same as in anonymous methods, delegate initializations, and explicit delegate creation expressions.
- As stated above: parameter type inference.
- Based on the former: inference of type arguments, if the delegate is a generic.
- If the method called is overloaded, the delegate type, if inferred from the context of the lambda parameter types, can be used for choosing the right method. This is an additional feature over anonymous methods.
Language-Integrated Query
Data integration is acronymed LINQ (Language-INtegrated Query), and it promises general query capability build right into the framework as well as the languages.
Note that I didn't mention the Common Language Runtime: all CLR support needed, such as iterators and generics is available in Whidbey already, which means that you can build your own query operator library similiar to the one proposed for orcas. Let's look at the triad of runtime, class library, and language compilers:
- The CLR supports generics and iterators in Whidbey.
- The .NET Framework class library provides the .NET Standard Query Operators in System.Query.Sequence class. Furthermore, there are support classes for relational data (DLINQ) that bring in ADO.NET, as well new XML classes such as XElement integrating XML (XLINQ) - both DLINQ and XLINQ are part of the LINQ project.
- The compilers support SQL syntax (known as query expressions or query comprehension) - VB.NET some more than C#, although it isn't standard SQL, and it maps pretty much one-to-one to using the standard query operators. VB.NET even supports XML literals, and even extended late binding for the XML types such as XElement.
Features used in Query Operators
- Extension Methods: syntactic sugar, "Shared Methods", aka module functions, masquarading as instance methods.
- Lambdas: simpler syntax for anonymous method callbacks (typically inferring the type arguments for generic delegates used).
- Overloaded Generic Delegates: System.Query.Func family for ad-hoc construction of delegate types.
- Tuple Types: used for projection, aka, select. They are types that the compiler generates, not a CLR feature.
- Iterators: used as generators, for on-demand operations.
Example: Query Operators for Conversion
Everett: none-type-safe delegate pointing to regular callback:
delegate object Converter( object arg ); IEnumerable Convert( IEnumerable source, Converter converter ); object TypeToTypeInfoEx(object arg){ return new CTypeInfoEx((Type)arg); } void Test(){ IEnumerable result = Convert( aTypes, new Converter(TypeToTypeInfoEx) ); }
Whidbey: generic delegate type, anonymous method:
delegate TargetType Converter<SourceType, TargetType>( SourceType arg ); IEnumerable<TargetType> Convert<TargetType>( IEnumerable<SourceType> source, Converter<SourceType, TargetType> converter ); void Test(){ IEnumerable<CTypeInfoEx> result = Convert<CTypeInfoEx>( aTypes, delegate(Type tp){ return new CTypeInfoEx(tp) } ); }
Orcas: lambda expression:
delegate TargetType Converter<SourceType, TargetType>( SourceType arg ); IEnumerable<TargetType> Convert<TargetType>( IEnumerable<SourceType> source, Converter<SourceType, TargetType> converter ); void Test(){ IEnumerable<CTypeInfoEx> result = Convert<CTypeInfoEx>( aTypes, tp => new CTypeInfoEx(tp) ); }
Orcas: like above, but with implicitly typed local, extension method and using the conventional Func delegate generic:
delegate TR Func<T0, TR>(T0 arg); IEnumerable<TargetType> Convert<TargetType>( this IEnumerable<SourceType> source, Func<SourceType, TargetType> converter ); void Test(){ var result = aTypes.Convert( tp => new CTypeInfoEx(tp) ); }
Questions and Comments
API
Func family type parameter ordering convention (return type last):
- PRO VB syntax
- PRO lambdy syntax
- CON C# syntax
C#
VB.NET
- Does explicit late binding mean that late binding still occurs implicitly if type inference is not possible (more complications)?
- Is duck typing like per-type exceptions from Option Strict On (for the purpose of type conversion, not member invocation)?