September 2005 - Posts
Part I: Lambda expressions, initial impressions.For me, the most important new technology unveiled at PDC was LINQ, and the underlying language enhancements that make it possible.
It’s been about two weeks since PDC, so I’ve gotten caught up (sort of) with work and I’ve had a little time to let the new concepts sink in. However, I’ve had precious little time to actually write code based on C# 3.0, so this entry is based on my initial impressions, and not a lot of detailed research. (Yes, I’ll be doing much more detailed research, but I haven’t had the time yet. Like everyone else, I’m learning all these new tools.)
I’m going to discuss these features from the standpoint of the C# language, rather than the LINQ use cases. The LINQ use cases are the driving force behind these new features, but I believe the C# community will find many uses for object initializers, query expressions, extension methods, lambda expressions, anonymous types, and even local variable type inference. We’ll likely stumble on a number of anti-patterns for these tools in our quest for great new uses. It’s going to be a fun time.
Lambda Expressions
Everyone, repeat after me: “Functional programming is not pure evil.” Feel better? Good. Functional programming idioms can be very powerful. However, Functional Programming is rarely the simplest path to the simplest solution. (Anyone that used emacs and wrote extensions in e-LISP knows what I mean.)
That is, in my opinion, what will be incredibly cool about Lambda Expressions in C#: You can add functional programming idioms to an object oriented language. You’re not constrained to a single set of design patterns. Developers will need to grow some new skills in order to choose the right idiom for the right problems. I’m not yet sure how easy that will be. Clearly, the query expressions are built using Lambda expressions. It seems that Lambda expressions might be able to serve where C++ function objects were used. At least, that’s one of the things I’d like to try.
In addition, functional programming is a powerful tool for very dynamic systems. You are essentially treating code (or algorithms) as data. Would it be possible to mix remoting and lambda expressions to do powerful things? Or, is it too dangerous from a security standpoint?
The downside of lambda expressions, and functional programming in general, is the complexity the follows from the syntax, and the expressiveness. One line of code compiles into function calls that call other methods that change program state that introduce bugs that are hard to find. It’s harder to examine code and quickly see what’s happening. That’s going to be where the C# community develops best practices for how to leverage this feature to create new exciting code, without creating mountains of babel.
Well, back to work. I’d meant to write a blog entry on everything new in C# 3.0. That’s not going to happen. However, the great thing about blogs: I can just continue to add more content here. I’ll be back to discuss other C# features.
A C# 2.0 program to cycle wallpaperI decided to extend a sample at coding for fun that lets you change your desktop wallpaper (you know, just for fun).
My version lets you pick a directory with any number of image files, and it will cycle through the images at regular intervals.
My reason for this update was simple. This version (http://www.srtsolutions.com/public/item/66746) was on the family computer, but there was a problem. It only ran if you were in the administrator group. The sample was written so that it created a bitmap file in the Windows System directory. So, when I went to all non-admin accounts, that capability was lost.
My version uses a users' local ApplicationData path for temporary bitmap images, and therefore runs for limited users.
Have fun, and the usual disclaimers apply.
The original Setting Wallpaper sampleA simple managed application to set your desktop wallpaper
My updatesCycling wallpaper
From building web service APIs that support multiple message schemasI wrote earlier about a technique to build a web service with minimal endpoints that support multiple schemas (http://www.srtsolutions.com/blogs/billwagner/2005/05/03/id91025.aspx).
I received a question about the technique:
"
The benefit is obvious - plugable extension of a running service.
One question still remains - how do you tell the consumers of the service what request produces what response. The only way I see is type naming convention where there is a unique pair per "operation". This may result in a slight type bloat as now type reuse is not possible.
"
It turns out that this is not as much of an issue as it first appears. Yes, it does add more types. However, there is a one-to-one correspondance between request types and response types. That means it's a very simple matter to produce a layer of code that isolates this issue from all user's of your type.
Furthermore, where this technique really enhances web service maintainabilty over time is when you modify a request / response pair over time. Updated clients send the updated request, and receive the updated response. Older clients send the older request (which should still be valid at the server), and ignore any additions in the updated response.
I'm not necessarily advocating that every webservive have one endpoint. Rather, that this technique does provide an elegant way to update a web service over time.
What comes next?One of the comments on an earlier entry (http://www.srtsolutions.com/blogs/billwagner/2005/06/21/id93158.aspx) asks if I'm going to write an updated version of Effective C# for version 2.0.
I'm not certain, for two reasons. First of all, my goal with the content in Effective C# was to ensure that all my recommendations continue to be valid with version 2.0. By and large, I think that's true. (Some of the boxing and unboxing advice changes with generics, and the garbage collector got some performance improvements.)
However, there are a lot of new techniques that developers can make use of. I intend on writing about it. I'll post announcements as these activities become public. However, I am working on an outline to cover best practices for C# 2.0, and beyond.
Is var good, bad, or ugly?
On var and C#
Dan Fernandez wrote recently on the var keyword in C# 3.0. He is very
thorough about how var works. I’m going to try and add to his commentary with
discussions about my initial thoughts on best practices for var and C#. The
usual caveats apply: This is some initial impressions, because it’s new to all
of us. I’m still making up my own mind about when it’s best to use var, and when
it’s best to avoid it.
Dan starts with this simple example (pasted from the blog posted linked
below):
Before 3.0
string myString = “hello”;
int myInt = 5;
float myFloat = 5.5f;
After 3.0
var myString = “hello”;
var myInt = 5;
var myFloat = 5.5f;
It’s critical that you understand what the C# 3.0 compiler does with respect
to typing here. In both cases, the IL will show that myString, myInt, and
myFloat are string, int, and float, respectively. It’s not weakly typed, or even
‘object’ types.
So, the first complaint comes: “Doesn’t this just make the code less
readable?”. In this instance, my answer would be ‘yes’. This simple example is
simply not a good usage for the var keyword.
Pulling one of his later examples (same blog entry), you can see why var was
added to the language:
var result =
from s in aBunchOfWords
where s.Length == 5
//Creates a new anonymous type
with name/value pairs
selectnew {Value=s, Length=s.Length,
FirstThreeLetters=s.Substring(0,3)};
//Print
values
foreach (var x in result)
Console.WriteLine("Value: {0}, Length:{1},
SubString:{2}",
x.Value, x.Length,
x.FirstThreeLetters);
This
prints:
Value: Hello, Length:5,
SubString:Hel
Value: World,
Length:5, SubString:Wor
Now you see why var is needed: The type of ‘result’ is
IEnumerable<something>. The only problem is that ‘something’ is named by
the compiler: you have no idea what is it.
The conclusion: Without ‘var’, LINQ gets too painful to use. You’d need to
define your own types for every different query you generate in every
application you write. It’s not that useful, and we’d probably end up with the
same kind of code we have now. You know, you’d define a type that contained
every column and then just leave some columns as nulls on any query that doesn’t
use them. Wasteful, and error-prone.
Great, that’s two very obvious examples: when var is almost necessary, and
when var just creates poor code. Where life gets very interesting is when you
fall somewhere in the middle. On the one hand, using var to save typing might
make sense in some occasions. The right hand side of the assignment is
sufficient to create clarity:
var rect = new Rectangle ( … );
var result =
myCollection.GetEnumerator();
The second line doesn’t necessarily tell me the type of result, but I can
easily get a good understanding of what it is. I’m not sure I prefer var, or
naming the variables.
Other uses get closer to the unreadable case:
var thing = MyClassFactory.CreateThings();
I intentionally chose rather vague names to increase the un-readability of
the code. In practice, context, and better class names probably makes this
construct a reasonable practice.
So, what do I really think about var, its usefulness, and its effect on code
readability? First of all, var is needed in LINQ. So get used to it. Secondly,
two reasonable coding practices you should be using anyway will keep code
readable, even if everything were declared with the ‘var’ keyword:
First, define class (or struct) names that clearly state the type’s purpose.
Vague names create unreadable code.
Second, shorter methods will improve readability. If you can see the
initialization of a type, you know what it is, or at least what the usage is for
that type, in that method.
So, var can decrease readability, but I think that will be a problem if your
code is already not very readable.
LINQ: The purpose of varDoes it help or hurt readability
Response to a recent blog post by Krzysztof Cwalina.Earlier this week, Krzysztof wrote about a possible change to the API design guidelines: allowing value type EventArgs. (See links for the full post). The argument for it is that it will make raising events a little cheaper. Krzysztof points out a couple issues with changing the definition of EventHandler< T >, and asks if the change is more trouble than it’s worth. I believe it would be a bad idea. I think it creates more trouble than it solves.
One solution is to remove the constraint on EventHandler< T >. Currently T must inherit from EventArgs. If the constraint were removed, I think that it (in practice) it would be much more difficult to use covariance with event handlers. That would be a problem.
The second possibility is to define a marker interface, say IEventArgs, to mark a type as an event args. That’s really not much better. I’ve never liked marker interfaces as a design idiom. (Even the Java community has admitted it was a bit idea). An interface should define some behavior.
Finally, I think the performance benefits are very small. Event args probably won’t live in memory for very long. It’s highly probable that an event args derived object will never get promoted out of generation 0. That minimizes the cost of allocation and collection. The cost is not much more than incrementing and decrementing the heap pointer. (Yes, that’s an over-simplification, but not by much.)
So, for me at least, this is one enhancement request that should be declined.
Krzysztof's postValue Type Event Args: yes or no?
For everything else.... Oh, never mindCost of PDC: $1500
Hotel (5 nights): $950
airfare: $375
Having the C# Product unit manager recommend your own book to you....
Priceless.
<short backstory>
At PDC, a number of RD's were invited to spend some time with members of the C# team to discuss the language, and how we interact with customers. I mentioned that most of the writing I do is meant to help C# developers learn best practices for working with the C# language, and I was looking for more resources from the team to help. Scott Wiltamuth's answer had the whole room laughing.
</short backstory>
Hopefully, that means he thought the advice was on point.
He can sum up new features very quicklyIn Anders' talk on LINQ, one of the attendees asked him (rather pointedly) if LINQ was going to turn out like Ojbect Spaces. He replied, "I'm not in the habit of building technolgy that doesn't get released."
Today, in his talk on C# 3.0, he went to the 3rd slide in his deck and pointed out that "All the new features in the C# language fit on one slide."
That's an incredible accomplishment. There is so much that will make developers more productive in C# 3.0, and the language was not perturbed much. That's a great feat of design.
So, I upped the anteI was chatting with some people from A-W this afternoon, and they mentioned that the PDC marketplace store was running out of Effective C#.
So, I signed the remaining 7 copies.
(And, if you see me and ask nicely, I'll personalize my signature for you, even if you bought one of the copies before I signed them.)
10 RDs, 2 hours, free beer, and free foodLast night, a number of the Regional Directors here at PDC spent the early part of the evening giving a series of very short (10 - 15 minute) talks on a variety of topics. Folks saw everything from Atlas, InfoCard, Windows Form 2.0, The My namespace, new managed C++ extensions, and more.
The PDC Underground homepageThe full list of speakers and topics
I haven't blogged, but I wrote an articleI wrote the review of yesterday's keynote for FTP Insight. I don't cover everything, but concentrated on the ideas that were important for developers.
I wrote another one for tomorrow, but I don't want to scoop my own article.
My impression of the keynote.Great new tools for developers.
On immutable structs, structs, and classesI received the following question that relates to Item 7 in Effective C#. It’s not strictly an errata, so I thought I would post it here for general discussion:
In Item 7, you recommend the use of immutable structs. I am puzzled by why you would recommend structs and not immutable classes. It seems to me that one of the main benefits of immutable objects is that there is no need to copy them; you can pass references to them all around your program without any worries that they might get changed. But structs automatically get copied every time they get passed anywhere. You gain a little bit of efficiency by not having to reference them, but at the price of having to keep making more and more copies of whatever fields your struct has. It seems to me that unless you are concerned about thread safety, you might as well make a struct mutable, because it is going to get copied anyway.
You could, of course, put "ref" on all of the methods that handle your struct, but that seems like you're back to the equivalent of just using immutable reference types, and you've done it in a goofy roundabout way that is liable to confuse somebody else who has to maintain your program.
(There are other reasons I don't like using structs. They look exactly like objects, and they can be passed to methods and such that are expecting objects, which again can lead to some heavy confusion to a maintainance programmer.)
I’ll boil this down to three questions:
1. Why use structs at all?
This is the subject of Item 6. The short answer is that classes support polymorphism, whereas structs do not. (Yes, I’m simplifying. Structs are derived from System.Object, so they do support all the methods from System.Object.) However, removing support for inheritance, virtual functions, and the other tools of object – oriented programming gives you some increased efficiency: All methods are statically bound, which increases the likelihood of inlining. In addition, there are no heap allocations, and no corresponding workload for the garbage collector.
Sometimes you don’t need the extra power of a class, so the simpler tool is the best one.
Your closing comments are all valid: structs do complicate many things in a large program. Because of that I would guess that 95% of the time, I pick a class. That 5% is important and will often make a program more efficient.
2. Why should structs be immutable?
Structs should be immutable because they are simpler. Once created in a valid state, they remain so. It’s also true that a mutable struct probably has a broken GetHashCode() method, but that’s the subject of Item 10. Finally, from a design standpoint, structs usually represent a single datum: something that is replaced as a whole, rather than modified. Immutability would support that.
3. Why not use immutable classes?
I never said not to use immutable classes. In fact, immutable classes are worth creating for many of the same reasons as immutable structs: they are simpler to code, their validity is easier to enforce, side-effects are less likely to introduce bugs, and the list goes on.
But, at some point, your program modifies its state. So, an item dedicated to creating immutable classes would be saying “use immutable classes, except when program efficiency means that creating a copy would be way too slow”. In many cases, that can be re-stated as “if you can support immutability for this type efficiently, it’s likely to be a good candidate for a struct.”
He didn't ask, but I'm pointing it out anywayMartin Shoemaker had a very moving experience while travelling yesterday.
Read it, and examine what you have done, and are doing.
Martin's travel storyA day travelling with folks affected by Katrina
Josh is now an official INETA speakerJosh Holmes, (http://www.srtsolutions.com/public/blog/19990) has been added to the INETA Speakers Bureau.
Our .NET User Group (www.migang.org) and the Ann Arbor Computer Society (www.computersociety.org) are both lucky enough to have heard him speak more than once. He's dynamic, energetic, and has a great depth of knowledge. I'm happy that he's one of the principals at SRT Solutions.
While I'm particularly happy for Josh, there were eight other fantastic people added to the INETA Speaker Bureau at the same time. They are:
John Alexander
Miguel Castro
Bill Evjen
Julie Lerman
Chris Menegay
Ted Pattison
Les Pinter
Bill Vaughn
So leave me a noteBoth Josh Holmes (http://www.srtsolutions.com/public/blog/19990) and I have taken the plunge and enabled public commenting on our blogs. So, feel free to leave us a note.
The comments are moderated. My own editing policy is simple: If what you say is on-topic, and no worse than PG language, it will stay.