C# in Depth

Cover of C# in Depth
Order now (3rd edition)

(You are currently looking at the first edition version of this page. This page is also available for the second and third editions.)

Notes for Chapter 8: Cutting fluff with a smart compiler

8.1: Automatic properties - easy to implement (which doesn't mean "cheap")

I'll let Eric speak for himself, in response to the statement that "Our first feature [automatic properties] is probably the simplest in the whole of C# 3":

It was by far the easiest to implement. Peter Hallam did it in about an afternoon. (Of course, the implementation cost is a tiny fraction of the design, testing, documenting, etc, cost. There are no cheap features, only some which are less expensive than others.)

8.1: "Fat" properties?

Apparently automatic properties were called "fat" (or perhaps "phat") properties for a while internally. I can't think why, given that they're the slim version of normal property implementations! Of course, this kind of thing often becomes a piece of in-house terminology for no discernible reason at all.

8.1: Why exposing properties rather than fields is best practice

In chapter 8, I asserted that you shouldn't write non-private fields - that using properties is regarded as best practice. I didn't explain why, however - but I've now written it up as an article.

8.2.1: "var" isn't "variant" - "object" is!

I go to great lengths in the book to explain that the use of implicitly typed local variables (var) isn't the same as making the code dynamically typed, or introducing the Variant type from COM or VB6. However, we already have something approaching that - object! If you declare a variable as being of type object, you can store whatever you like in it. That's not true of implicitly typed variables.

8.2.2: Additional (and inconsequential) restriction on implicit typing

The following method call and assignment is legal. Insane, but legal.

int j = M(j=10);

It has the semantics of this code:

int j;
int temp;
temp = (j = 10);
j = M(temp);

Okay, fair enough - hopefully most readers know that code like this is a recipe for disaster. However, let's try adding implicit typing to the mix:

var j = M(j=10);

How do we find out the type of j? We look at the return type of M.
How do we work out which overload of M so use? We look at the type of j.
In short, there's a chicken and egg problem, so this is declared to be illegal.

8.2.3: Eric on the pros and cons of implicit typing

This was such a great comment, I had to include it verbatim. You'll see it reflected so some extent in the book, but it's worth having the full version here.

All code is an abstraction. Is what the code is “really” doing is manipulating data? No. Numbers? Bits? No. Voltages? No. Electrons? Yes, but understanding the code at the level of electrons is a bad idea! The art of coding is figuring out what the right level of abstraction is for the audience.

In a high level language there is always this tension between WHAT the code does (semantically) and HOW the code accomplishes it. Maintenance programmers need to understand both the what and the how if they’re going to be successful in making changes.

The whole point of LINQ is that it massively de-emphasizes the "how" and massively emphasizes the "what". By using a query comprehension, the programmer is saying to the future audience "I believe that you should neither know nor care exactly how this result set is being computed, but you should care very much about what the semantics of the resulting set are." They make the code closer to the business process being implemented and farther from the bits and electrons that make it go.

Implicitly typed locals are just one small way in which you can deemphasize the how and thereby emphasize the what. Whether that is the right thing to do in a particular case is a judgment call. So I tell people that if knowledge of the type is relevant and its choice is crucial to the continued operation of the method, then do not use implicit typing. Explicit typing says "I am telling you how this works for a reason, pay attention". Implicit typing says "it doesn’t matter a bit whether this thing is a List<Customer> or a Customer[], what matters is that it is a collection of customers."

8.3.1: Town or city?

In listing 8.2, the Location class has a country and a town. It was noted that most people - at least in the US and Canada - would usually have chosen "city" instead of "town". It's possible that this is a US/UK distinction, as in the UK it's feasible to tell people from elsewhere in the country the name of a reasonably large town you're close to and give more information than just the closest city.

The most practical reason for my choice, however, is that I wanted to distinguish between Purley and Reading in the example, while sticking with Tom and his friends for data. In fact, Purley is more of a village than a town, but if we'd gone with "city" I'd have needed a different set of people entirely.

8.3.4: Fear is not the enemy...

When describing object and collection initializers, I talk about the code being clearer through having less fluff. Eric describes it in a more precise way:

Again, redundancy is the enemy of information density. Only redundancy which contributes to the understanding of the code should be encouraged; other kinds of redundancy are discouraged.

8.3.4: Ages vs dates of birth

In a few examples, I have used Age as a property of a Person - a property which is writable. In real code, this is bad idea. The moment after an age has been set, it is inaccurate - whereas a date of birth lasts forever. The age can always be calculated as a read-only property. This also allows the type to be (potentially) immutable.

I used age in the examples as a simple number which could easily be attached to a person - but this shouldn't be copied in real code. In truth, I suspect that very little code shown in books should be copied verbatim. The kind of code which is useful for teaching purposes often highlights one area at the expense of others, partly through the need for brevity in print.

8.5.1: Introducing LINQ

LINQ is complicated. It requires a lot of somewhat intertwined features, some of which don't make much sense until you see the bigger picture. Eric suggested that the "bottom up" way I've approached it in the book is possibly best for a book, and that a "top down" approach works better in a live presentation.

I've tried to present in a top down manner, and not been terribly successful - but I can do the bottom up style fairly easily, given enough time and an interested audience. I suspect this has more to do with my presentation skills - and frankly the experience of writing the book in a bottom up manner - than it has to do with the soundness of the idea itself. I'll be keeping an eye out for how other presenters tackle the topic. Feedback is welcome.

8.5.2: Anonymous types in VB, and immutability

As I point out in the book, anonymous types in C# are always immutable. I only recently learned that in VB, anonymous types can be wholly or partially mutable.

That doesn't sound too bad - choice is good, right? But anonymous types are mutable by default in VB. They're only immutable for properties decorated with Key. Ouch.

While it's obviously good that different languages can choose different paths, it seems odd to me that by default VB has chosen against immutability, while the rest of the world is trying to embrace it for its threading goodness (and other benefits, of course). I'm happy with C#'s choice to make anonymous types immutable, and I'd hope that if the C# team had decided to allow mutability, they'd have made that an explicit choice, with immutability the safer default.

It's really important that VB developers understand this, by the way - various LINQ operators such as Distinct rely on equality and hashing, which are only applied to immutable properties for anonymous types... if you're going to use those operators in VB, you must remember the Key modifier.