C# 1.0 brought us managed code. C# 2.0 introduced generics. C# 3.0 introduced LINQ, which has helped to incorporate a lot of functional programming features into the language and solve some of the dissonance between the language and relational data. Finally, today, we’ll discuss what is coming up in C# 4.0, namely dynamic programming.
There are several trends in the industry that have shaped this release of C#. The first is a movement toward more declarative styles of programming, such as XAML, CSS, HTML and other markup languages. Dynamic languages such as Python, Ruby, Lua, and even JavaScript can be seen in practice from the World Wide Web to the World of Warcraft. And with the increase of multi-core processors, concurrency is becoming more important, especially from the perspective of what programming languages should support.
When we write code in the imperative style that the industry has been entrenched in for 40 years, we write (of course) what we want done, but in excruciating detail HOW we want it done. In a sense, we overspecify the solution in imperative style. This can create optimization problems and side effects, because the compiler has no choice but to execute step-by-step. However, if you use something like LINQ or another declarative style, you can say things in a more abstract sense such as “order by” or “group by.” That gives the compiler a much better chance of optimzing the code better, or even being able to execute it in parallel. This helps to push languages, including C#, in the direction of supporting more declarative features.
Dynamic vs static is an argument that has been around since programming languages were first born. While each paradigm has its own strengths and weaknesses, ideally you can borrow from both buckets to create something great.
Writing parallel code is hard. Moore’s Law has allowed us to largely ignore it, because the clock speed has simply increased over time. However, that clock speed has leveled out now (around 2.5 GHz) and instead of scaling up the speed, engineers are adding more cores. Unfortunately, there’s no magic bullet for programmers to write concurrent applications. You have to really sit down and think about how to write concurrent applications for multicore processors. The multicore trend presents a lot of interesting challenges, especially since traditionally we think of multiprocessing as the same as multithreading, where you split up work among threads on one processor. Now, we are talking about running discrete tasks on separate cores, executing tasks in parallel.You might have heard about Parallel Extensions for .NET. These extensions will allow you to write code that, through the use of lambda expressions, translates to code that will execute in parallel. This offers a glimpse into where C# is headed down the road, as well.
To VB and C# users, co-evolution means:Cooperation – Knowledge & technology transfer between the two teamsA little bit of rivalryInnovations in one language inevitably turn up in the other. C# introduced VB concepts such as: 1st class enumerations, properties, events. Dynamic binding, optional parameters, named arguments have all been used in VB for a long time, and now C# has the same luxury.Likewise, VB 8.0 introduced many concepts initially implemented in C#, such as overloaded operators, unsigned types, and generics. VB 9.0 brought LINQ, which was the result of quite a bit of cooperation between the C# and VB teams.However, users of VB and C# have a storied history of “sibling rivalry.” Invariably, with every new release, one language gets a cool new toy, and the other is left asking, “Where’s my toy?”For example: Nullable types in C# 2.0 (not implemented til VB 9.0), automatic properties in C# 3.0 (not implemented til VB 10).The vision is to have a tight cooperation between both teams to commit to developers that capabilities will show up in both languages at pretty much the same time. The next release of these languages brings us a step closer to that vision.
C# 1.0 brought us managed code. C# 2.0 introduced generics. C# 3.0 introduced LINQ, which has helped to incorporate a lot of functional programming features into the language and solve some of the dissonance between the language and relational data. Finally, today, we’ll discuss what is coming up in C# 4.0, namely dynamic programming.
Where the CLR is a common platform for statically typed objects, the DLR unifies dynamic programming on top of .NET. The core infrastructure in the DLR includes Expression Trees (such as LINQ), dynamic dispatch to different binders, and call site caching to avoid having to resolve to the same location more than once. IronPython and IronRuby already support the DLR. Now, with C# 4.0 and the next release of VB, these languages can target the DLR as well.The way the DLR interfaces with other platforms is via binders. There is an object binder that maps to statically typed .NET objects. There is a JavaScript binder that allows us to bind directly to javascript in Silverlight applications (and bypass the COM-stile invocation). Similar binders exist for Python, for Ruby, and also for the Office object model.
How things used to look, with multiple overloads
Now, with optional and named params
Getting rid of the NASTY style of COM interop thanks to optional & named arguments and the Office library
Code now looks the way it was intended to look. There is now special support for indexed properties in COM objects. You can omit the ‘ref’ keyword in some cases. One feature (which can be enabled or disabled) is an automatic mapping from a static object type to a dynamic type. Another feature is No PIA (Primary Interop Assembly). So when you run the final app, you don’t need that primary assembly at all. Those types are embedded into the app now.
.NET arrays are co-variant, which means you can pass a string array as a less-derived object array. However, .NET arrays are not *safely* covariant. It will compile, but it will fail at runtime. For arrays of reference types, every assignment has a dynamic type check that checks what you are assigning is the same type as the actual array. Now if we had written this as using Generics, this would have failed at compile time. Until now, C# generics have been invariant, meaning those two types are not compatible. But C# 4.0 supports safe co- and contra-variance.It’s safe because IEnumerable is a read-only interface, there is no way to put new things in. Therefore, it’s safely co-variant.
Out: T gets restricted in output positions only (such as the result of a method call, result of a method accessor). T couldn’t be a parameter, because that would initiate dynamic type checking.So when things are co-variant, they can be treated as less derived.In the case of contra-variance, T is marked as contra-variant via the ‘in’ keyword. Contra-variant things can be treated as more derived.
Variance is restricted to interfaces. Technical term for our implementation is “statically checked definition site variance.”Just like arrays, value types are always invariant. Just as an int array is not an object array, an IEnumerable of int cannot be treated as an IEnumerable.
Now that C# 4.0 supports variance, some of the existing interfaces and delegates have been decorated with the appropriated variance annotations. While it’s interesting on a technical level, what this really does is allow you to do things in code that you previously wondered why you couldn’t do.
Meta-programming is used all over the place, from script environments, to dynamic code generation (entity framework, LINQ to SQL, Reflection.Emit). These technologies can be kind of painful to use. The C# compiler, going forward, is heading towards managed code. Currently it’s written in C++ (because you have to write the compiler to get the platform, of course). It’s a very classical compiler; source file goes in, assembly comes out. But it’s a black box.Going forward, we want to open up that box and give people access to cool things like meta-programming, REPL loops, etc. The possibilities here would be to embed C# code directly in things like workflow documents or domain-specific languages, using C# as a scripting language in some host environment, and more.
Optional and Named Parameters Optional parameters publicStreamReaderOpenTextFile( string path, Encodingencoding, booldetectEncoding, intbufferSize); publicStreamReaderOpenTextFile( string path, Encodingencoding = null, booldetectEncoding = true, intbufferSize = 1024); Named argument OpenTextFile("foo.txt", Encoding.UTF8); OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096); Arguments evaluated in order written Named arguments can appear in any order Named arguments must be last OpenTextFile( bufferSize: 4096, path: "foo.txt", detectEncoding: false); Non-optional must be specified
Co- and Contra-variance .NET arrays are co-variant string[] strings = GetStringArray(); Process(strings); …but not safelyco-variant void Process(object[] objects) { … } void Process(object[] objects) { objects[0] = "Hello"; // Ok objects[1] = newButton(); // Exception! } Until now, C# generics have been invariant List<string> strings = GetStringList(); Process(strings); C# 4.0 supports safe co- and contra-variance void Process(IEnumerable<object> objects) { … } void Process(IEnumerable<object> objects) { // IEnumerable<T> is read-only and // therefore safely co-variant }
Safe Co- and Contra-variance publicinterfaceIEnumerable<T> { IEnumerator<T> GetEnumerator(); } publicinterfaceIEnumerable<out T> { IEnumerator<T> GetEnumerator(); } out= Co-variantOutput positions only Can be treated asless derived publicinterfaceIEnumerator<T> { T Current { get; } boolMoveNext(); } publicinterfaceIEnumerator<out T> { T Current { get; } boolMoveNext(); } IEnumerable<string> strings = GetStrings(); IEnumerable<object> objects = strings; in= Contra-variantInput positions only publicinterfaceIComparer<T> { int Compare(T x, T y); } publicinterfaceIComparer<in T> { int Compare(T x, T y); } Can be treated asmore derived IComparer<object> objComp = GetComparer(); IComparer<string> strComp = objComp;
Variance in C# 4.0 Supported for interface and delegate types “Statically checked definition-site variance” Value types are always invariant IEnumerable<int> is not IEnumerable<object> Similar to existing rules for arrays ref and out parameters need invariant type
The Evolution of C# C# 4.0 Dynamic Programming C# 3.0 Language Integrated Query C# 2.0 Generics C# 1.0 Managed Code
Compiler as a Service Class Meta-programming Read-Eval-Print Loop public Foo Field Language Object Model DSL Embedding private X string Compiler Compiler SourceFile .NET Assembly Source code Source code Source code Source code
0 comments
Post a comment