Hanalei, Hawaii 9/2/2010
438 Posts and Counting

The C# Makeover

Wednesday, August 29, 2007 - This post was supposed to be all about Lambda Expressions and how you can use these to strip some serious lines of code from your application. As I started working with some examples it became clear to me that Scott Guthrie already said pretty much all that needs to be said about that. What's more interesting to me is what's happening to the C# language feature set! On one hand it looks like things are getting a lot cleaner and more fun (Extensions, the new Property declaration syntactic sugar, etc) but I have to tell ya - I'm starting to get confused a bit these new kids - vars and Lambda expressions, and what they're doing here. You might be thinking "what's so confusing about a var or a Lambda - dude that's CS 101!" and I'd say you're right. Why are they here in my statically-typed C#?

As far as technical things go - It's easy to understand how to use vars and Lambdas, it's harder to understand when or why to use them.
So let's get this out of the way up front: C# is a typed language; always has been, always will be. Microsoft is introducing some new keywords and abilities to C# with the 3.0 version that will allow it to be a little "looser" and more "dynamic" - but it's important to also understand that
vars and Lambdas were introduced to facilitate LINQ. You may now continue with your normally scheduled programming...
Given that - I think it's very important to understand what these things are doing "under the hood" so you can understand when to use them. Vars Are Not Ducks There are some who've compared vars to Ruby's (and other dynamic languages) ability to do type-interpretation on the fly (duck-typing), and that's not the case at all with vars. In fact I'll go so far as to say that it's not even close. Duck Typing (and dynamic-language programming in general) is a different approach and mindset altogether. I'll get to that later - for now I want to go into how vars work. Vars need to know what's coming in order to type themselves. You can't fool Mother Compiler - you can only hold her off for a bit. In this case a var is "late-typed" (or latent-typed) based on what you assign it to:
var myBadHabit = DateTime.Now;
If you compile this statement then look at the IL, you'll see:
.locals init ([0] DateTime myBadHabit)
When using LINQ, a var is "late-typed" for you to be the return set (the "select" statement) so that you can use a typed result set for the query return. So in the following LINQ query, "result" is our Anonymous Type that's typed as ... <AnonymousType>:
Northwind.NorthwindContext db = new NorthwindContext();

var result =

      from products in db.Products

      select new {products.ProductID, products.ProductName};
If I open up reflector, The IL looks like this (it's kind of fun to see LINQ's Expression Tree here and all the code that's saved by the sugary LINQ syntax):
ParameterExpression CS$0$0000;

NorthwindContext db = new NorthwindContext();

var result =

db.Products.Select(

        Expression.Lambda(Expression.New((ConstructorInfo)

        methodof(<>f__AnonymousType0<int, string>..ctor, <>f__AnonymousType0<int, string>),        new Expression[]

        { Expression.Property(CS$0$0000 = Expression.Parameter(typeof(Product), "products"),

        (MethodInfo) methodof(Product.get_ProductID)),

        Expression.Property(CS$0$0000,

        (MethodInfo) methodof(Product.get_ProductName)) },

new MethodInfo[] { (MethodInfo)

        methodof(<>f__AnonymousType0<int, string>.get_ProductID, <>f__AnonymousType0<int, string>),

        (MethodInfo) methodof(<>f__AnonymousType0<int, string>.get_ProductName, <>f__AnonymousType0<int, string>) }),

new ParameterExpression[] { CS$0$0000 }));
Of particular note here is <>f__AnonymousType0<int, string> - this is my return type (since I'm saying select new ProductID and ProductName). Moreover, looking around Reflector a bit I can see that this class is declared as part of my project (as well as a note saying this was compiler-generated). I went ahead and took a look at this Anonymous Type and here's what it decompiles too (note the use of the constructor, as well as the methods hidden from the debugger - wonder why they do that?):
[CompilerGenerated, DebuggerDisplay(@"{ ProductID = {ProductID}, ProductName = {ProductName} }", Type="<Anonymous Type>")]

internal sealed class <>f__AnonymousType0<<ProductID>j__TPar, <ProductName>j__TPar>

{

    // Fields

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]

    private readonly <ProductID>j__TPar <ProductID>i__Field;

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]

    private readonly <ProductName>j__TPar <ProductName>i__Field;    // Methods

    [DebuggerHidden]

    public <>f__AnonymousType0(<ProductID>j__TPar ProductID, <ProductName>j__TPar ProductName)

    {

        this.<ProductID>i__Field = ProductID;

        this.<ProductName>i__Field = ProductName;

    }

[DebuggerHidden]

    public override bool Equals(object value)

    {

        var type = value as <>f__AnonymousType0<<ProductID>j__TPar, <ProductName>j__TPar>;

        return (((type != null) && EqualityComparer<<ProductID>j__TPar>.Default.Equals(this.<ProductID>i__Field, type.<ProductID>i__Field)) && EqualityComparer<<ProductName>j__TPar>.Default.Equals(this.<ProductName>i__Field, type.<ProductName>i__Field));

    }

[DebuggerHidden]

    public override int GetHashCode()

    {

        int num = 0x6d97624d;

        num = (-1521134295 * num) + EqualityComparer<<ProductID>j__TPar>.Default.GetHashCode(this.<ProductID>i__Field);

        return ((-1521134295 * num) + EqualityComparer<<ProductName>j__TPar>.Default.GetHashCode(this.<ProductName>i__Field));

    }

[DebuggerHidden]

    public override string ToString()

    {

        StringBuilder builder = new StringBuilder();

        builder.Append("{ ProductID = ");

        builder.Append(this.<ProductID>i__Field);

        builder.Append(", ProductName = ");

        builder.Append(this.<ProductName>i__Field);

        builder.Append(" }");

        return builder.ToString();

    }

// Properties

    public <ProductID>j__TPar ProductID

    {

        get

        {

            return this.<ProductID>i__Field;

        }

    }

public <ProductName>j__TPar ProductName

    {

        get

        {

            return this.<ProductName>i__Field;

        }

    }

}
The upshot here is that vars generate some serious code - all for good reason when using LINQ: But NOT for a good reason if you're being lazy - which is the point of this whole post.
If you find yourself using "var" anywhere that's not within a LINQ statement, it's probably not a good idea.
It's not duck-typing, and the compiler doesn't "infer" anything - you tell it exactly what you need and it will make it for you (which is kind of groovy). I think it's worth going further here, showing explicitly what duck-typing is and why some people love it. I'll be using Ruby (surprise) for these examples. Ruby, Quack For Me Phil Haack wrote up a nice post about some "duck-typey" feature in C#, and how they can benefit you. While I disagree that these things are anything but "late" or "coerced" typing - I totally agree with the spirit of the article:
The problem for me is [that] this is a lot more code to maintain just to get around the constraints caused by static typing. Is all this additional code worth the headache?
When C# or Java developers talk about dynamic languages, they're usually dismissed as "silly" or "hippy" languages that slow down a processor and bring a non-threaded web server to it's knees. This is all changing as servers get bigger, and popular web servers (like Apache and IIS) implement threaded CGI support. In fact IIS 7 is stating pretty clearly that it will run PHP and Ruby up to 5 times faster than other platforms, simply because of it's native threading/pooling model (using FastCGI). So don't be surprised to find yourself coding in Ruby someday (if you're not already). It takes a while to get used to not having types, but pretty soon you'll get the hang of the language, and in fact come to realize that:
Duck-typing is all about what an object does, not what it is - The Cuato Rule
To some that might read like a license to be sloppy. To a Ruby-head they see Java/C# as a reason to be verbose and "codey". In the spirit of Detente, and getting to know each other, let's take Phil's example of a Duck/Rabbit and put it in terms of code:
Suppose we have a method that takes in a duck instance, and another method that takes in a rabbit instance. In a dynamically typed language that supports duck typing, I can pass in my object to the first method as long as my object supports the methods and properties of duck in use by that method. Likewise, I can pass my object into the second method as long as it supports the methods and properties of rabbit called by the second method. Is my object a duck or is it a rabbit? Like the above image, it

A Ruby-head might point out that methods don't expect types, they expect abilities - which is sort of splitting hairs on semantics. But it's a valid point since that is the mindset of using a language like Ruby - it's all about what an object can do - because by God if it can, it will!

To do this I am going to use a "Mixin" in Ruby - which is sort of like an interface in C#, and sort of like an INCLUDE in C++. Essentially a Mixin is a module that allows objects to share functionality. In Ruby, a Mixin is considered an "Adjective" to the classes "Noun" (it defines an ability, or "flavor" of the class) - so in our case I'm going to create a Mixin called "Chatty" that will define a method called "greet" which will be shared among the classes:

module Chatty
    def greet(other_animal)
        puts "It's "+other_animal.class.name+" season! Not "+self.class.name+" season!"
    end
end

This method is simply looking at the class names of the objects involved, then outputting something to the screen. Easy enough - now I need to create the classes to implement the Mixin:

class Duck
    include Chatty
end

class Rabbit
    include Chatty
end

Not coincidentally, you need the "include" keyword in Ruby if you're going to use a Mixin - now each of these classes implements the "greet" method. You can overwrite this method if you want by simply writing a new one with the same name.

Finally, let's write out the method, remembering that each animal involved has to be able to "greet" the other:

def converse(animal, other_animal)
    if(animal.respond_to?(:greet) && other_animal.respond_to?(:greet))
        puts animal.greet(other_animal)
    else
        puts "I don't speak "+other_animal.class.name+"-ish"
    end
end

Notice in line 2 that I make a check to see if the animal involved can use "greet", and if not I output something appropriate. We don't care what "Type" of animals are involved here - only that they can greet each other. Now if I run this code:

bugs = Rabbit.new
daffy = Duck.new

converse(bugs, daffy)

The response is:

"It's Duck season! Not Rabbit season!"

This is exactly what Phil was talking about in terms of "I can pass in my object to the first method as long as my object supports the methods and properties of duck in use by that method" however I think it's very, very important to look at this in terms of function - not types. No methods expect a type - just the abilities of the type.

Compiler Freedom
Not having a compiler look over your shoulder for type errors can be a little scary. But dynamic language guys will tell you that you "just need to test more". That's a worth while idea since complete testing is always a good idea.

One of the really neat features of Rails is the way they can interpret methods that don't exist. To illustrate, suppose I have a database full of Ducks and Rabbits, and I want to run a query on the Ducks:

ducks=Duck.find(:all)

This will run a query which returns every duck. If I wanted to add some conditions, I could do that as well:

ducks=Duck.find(:all, :conditions => [:name => 'quackers', :age =>10])

And that works OK, but Rails also offers this little gem:

ducks=Duck.find_by_name_and_age('quackers', 10)

This last bit of code implements the "Missing#Method" exception catcher since this method doesn't exist - I made it up! It then parses the statement into SQL syntax! This works nicely since there's no compiler, and moreover - look at how that reads!

There's a price for this kind of thing, of course - I'll "duck" that and leave it up to you and your needs. If you're not running Twitter, something like Rails can be a good thing for you and your team.

Summary
I really dig that the DLR is going to be folded into .NET and we'll be getting access to all kinds of nice dynamic languages. I'll find it very interesting to see how the community reacts to it's presence. So far .NET has been all about static typing and, let's face it, some verbose code structures - it's nice to see this move towards brevity with things like the new property declarations and Lambda expressions.

What do you think of all this?

Related


Gravatar
Rob Conery - Wednesday, August 29, 2007 - Oh yah - I forgot to add that refactoring in Rails can lead to more load on server memory (caching) - so you pay a price for increasing response, but eating up server memory. I think this one thing is probably the biggest problem they had. It's really important to keep in mind that Twitter is charting new ground in terms of Rails - no one has ever had to deal with these issues before with Rails. So you gotta give em some slack. At the same time - I'm pretty sure 1 SQL Server and 2 to 3 IIS web servers could handle Twitter's load pretty easily. This is the benefit of compiled/managed code :).
Gravatar
Rob Conery - Wednesday, August 29, 2007 - @Adam: The Twitter team isn't saying what's causing the problems, but I think we can guess at this. Here's what we know: they've never "had more than 3 engineers" working on Twitter at any one time. They thank Rails for this and they also acknowledge that "the problem isn't Rails - [we didn't scale properly]". http://twitter.com/blog/2007/06/under-hood-at-twitter.html Given that - we now understand that the issue was "scaling" - meaning allowing your app to respond to growing user demand. I can't fault them - but Twitter is a glaring example of developer comfort vs. scaling, and Rails is the prime example of writing cleaner code versus writing for performance. My guess is that they got caught between refactoring (70%) while scaling up their servers (30%). This treadmill can really screw you, and if you mess it up... well you see what we saw over and over again (and still see). I don't know the server they're using, but I'm going to guess it's changed hands a few times and they've ended up with Apache. Apache can proxy/balance calls to other servers running on different ports - this is called "software balancing". I'm going to guess that with 3 engineers - this is what they did (and crossed their fingers). The most popular, lightweight CGI backend for this setup is Mongrel - a GREAT Rails server, but far from perfect. Apache/Mongrel has a lot of problems with "zombie daemons" that clog the process - this would explain why you wait and wait for an update, and nothing happens - there's no CGI daemon available for your request. I'm going to guess also that they changed their config a few times and got it wrong - this would explain being down for days while they tried to "get it right" and call in some help, probably via favors from friends cause these guys don't make much money at the service. They probably managed to get some servers in, and then wrestled with how to properly farm them out, and the how to setup hardware load balancer. Again - I'm sure they called in favors from friends for this cause it's big time work - get it wrong and boom! And that's just what we saw, more and more. I will stand up for Rails here and say that it wasn't Rails fault, per se, that Twitter's been offline so much. It's the fact that CGI sucks, and so does Apache , for this kind of thing. IIS got it right - thread pooling! Long answer - but in there I'm sure I hit on a few things that actually happened :).
Gravatar
Jerod Venema - Wednesday, August 29, 2007 - Hey Rob, Sorry to reply to this without referencing the actual post, but I can't figure out where else to do this :). I have a slight modification to SubSonic's RESTHandler that I'd like to submit as a patch; where can I do so? TIA, -Jerod
Gravatar
10 Links Today (2007-08-29) - Wednesday, August 29, 2007 - [...] The C# Makeover var, duck typing, linq, ruby on rails, c# [...]
Gravatar
Jim - Wednesday, August 29, 2007 - More features are a good thing in the right hands. On one hand, you have quality code built on top of the .NET framework (like Subsonic), and ugly hacks (most stuff on codeproject.com). Looking around my department at work, we don't have CS degrees, but we're still asked to build applications. I've seen a lot of bad code because somebody took advantage of a feature that Microsoft promotes, but Microsoft MVPs say to stay away from. E.g. the SqlDataSource. In Microsoft training, they show you how easy it is to use, but you're basically putting SQL right there in your page. A visiting Microsoft MVP told us to NEVER use the SqlDataSource. Anyway, new features are good, but only if used correctly.
Gravatar
Mike D - Wednesday, August 29, 2007 - I am amazed at how much I continue to learn from these fantastic posts. Keep it up and I hope you dig a little deeper in to Lambdas.
Gravatar
Haacked - Wednesday, August 29, 2007 - Great post Rob! Wouldn't you say that vars makes C# more dynamically, but lambdas make it more functional? It seems lambdas are orthogonal to whether the language is statically or dynamically typed. Am I off-base in saying that?
Gravatar
Rob Conery - Wednesday, August 29, 2007 - @haacked: I would say that, yes. Lambdas are the cornerstone (as you know) of functional languages (like F#, Scheme, and Lisp) but also play a key role in dynamic languages like Ruby. Building a hash from Lambdas is awesome - they're little dynamic methods! LINQ is built on this premise and I think require a certain level of dynamic-ness of a language to work well.
Gravatar
Eric Schoonover - Wednesday, August 29, 2007 - This was a great post, very informative, and educational. Thanks!
Gravatar
Brian Schroer - Saturday, September 01, 2007 - You said: "If you find yourself using "var" anywhere that's not within a LINQ statement, it's probably not a good idea." I think it's a great idea when you declare and instantiate in the same statement to use: var list1 = new List(); instead of having to tell the compiler twice, like this: List list1 = new List(); That's not syntactic sugar, it's syntactic Sweet'N Low - Helps get rid of unsightly fat code. I do think it would be lazy and a bad idea to declare: var myThing; ...and not assign anything to myThing until several lines later.
Gravatar
Brian Schroer - Saturday, September 01, 2007 - The comment processor thought my generics were HTML: I tried to stay that I preferred: var list1 = new List<PreferredCustomer>(); to <PreferredCustomer> list1 = new List<PreferredCustomer>();
Gravatar
Rob Conery - Monday, September 03, 2007 - @Michael: the entire purpose of the var keyword is for LINQ, and LINQ alone - it allows you to work with a typed result set. Nope - the inference happens when you type the keyword "var", and then finish the statement. The compiler is incapable of "inferring" anything at compile-time. At design time it can look to see what you're setting your var to, and then type it accordingly. At runtime (as the Ruby interpreter does) it can look at the value being passed in and decide what type it is. There is no inference here at all. In terms of "If you find yourself NOT using var, you need to ask why" - Huh? No way. @Brian - "great"? Huh? Are you hanging out with Micheal in a smokey room? "Having to tell the compiler twice" - When you "tell" the compiler about a variable, you first declare the type, then the value. Not sure how you're going to do otherwise is a typed language. If you use var, you're simply being LESS explicit about this truth: var ImToLazyToTypeThis = new ImNotTooLazyToTypeThis(); Seriously - please, for me, don't do this.
Gravatar
Michael Giagnocavo - Tuesday, September 04, 2007 - @Rob @Brian:

"If you use var, you're simply being LESS explicit about this truth:"

No you aren't:

var input = Console.ReadLine();
is identical to:
string input = Console.ReadLine();

var items = new[] {"a", "b", "c"};
is identical to:
string[] input = new string[] {"a","b","c"};

Go compare the IL or check the C# spec if you have any doubts :)

Some people feel strange by not writing things out. This is just because it's been beaten into us over and over again. C# allows us to have flexibility to be as generic as we want, while remaining 100% strongly typed and safe.

I'd actually be interested in talking with you in more depth to see what exactly your objections are in detail and understand why you have them.
Gravatar
Michael Giagnocavo - Tuesday, September 04, 2007 - http://blogs.msdn.com/stevecook/

Here's another example of using the "LINQ" features to do other, cool stuff. Look at the evolution from the imperative style (in comments of the first of the series just posted there) and compare it to later versions.
Gravatar
ian - Thursday, September 13, 2007 - "var ImToLazyToTypeThis = new ImNotTooLazyToTypeThis();" Classic. That class has no properties of any kind, since it would require too much effort to set them.
Gravatar
Rob Conery » Text Mining and Analysis With LinqToSql, Part 2 - Friday, September 21, 2007 - [...] query - this is a nifty feature that allows you to explicitly declare a type for the return. If you have issues with var abuse, this is a nice way to be a little clearer with your [...]
Gravatar
Brent Brown - Thursday, March 06, 2008 - Here's a differing opinion on the question of using "var" outside of a Linq statement.

http://resharper.blogspot.com/2008/03/varification-using-implicitly-typed.html