Bookmark and Share

Beef up params in C# 5 to solve Lambda Abuse

by KodefuGuru 8. April 2010 17:56

C# 4 introduced named and optional method parameters, which does a fine job of cleaning up method overloads. But a piece of the puzzle was left out. The params keyword could have been combined with named parameters to make it even stronger and address issues others have overcome by abusing other language features. To be fair, params works great with optional parameters. However, it is nearly unusable with named parameters.

Here’s an example of using params.

static void Main(string[] args)
{
    WriteLine("{0} {1}", "Hello", "World!");
}

public static void WriteLine(string format, params object[] args)
{
    Console.WriteLine(format, args);
}

Now let’s name the format parameter in the WriteLine call.

WriteLine(format: "{0}", "Hello World!");

You get the following error message:

Named argument specifications must appear after all fixed arguments have been specified

I believe this is a somewhat unfair message. The args parameter is an array of leftover parameters. The compiler could have been made intelligent enough to figure this out. There is only one way to use named parameters with params, and that is to name the parameter specified with the keyword.

WriteLine(format: "{0} {1} ", args: new[] {"Hello", "World!"});

This defeats the ease of use you gain with params, as the method works just as well without it.

Of more interest to me is utilizing parameter naming for a variable number of parameters. Imagine if the original code was written like this:

static void Main(string[] args)
{
    WriteLine(format: "{hello} {world}", hello: "Hello", world: "World!");
}

public static void WriteLine(string format, params dict<string, object> args)
{
    Console.WriteLine(format, args);
}

The code is a bit longer, but the format strings are more descriptive. Which is more understandable: {0}://{1}:{2}{3} or {protocol}://{host}:{port}{path}? I came up with this idea after noticing a reddit user was having an issue with the help for error message MSB3021. The message is “Unable to copy file "{0}" to file "{1}". {2}.” The description on MSDN didn’t tell you the meaning of each part… it’s really just a copy of the format string. You can infer that {0} is source and {0} is destination, but what is {2}? I hope it’s description, but it isn’t clear.

This would also solve the same problem the Lamba Abuse pattern solves, but it does so in a cleaner manner using a feature that fits more with its original intent.

For a quick refresher, here’s how the lambda abuse version of WriteLine would look, calling into the Hash class from MvcContrib. I added a method to Hash to encapsulate the functionality of instantiating Hash and replacing the format tags.

static void Main(string[] args)
{
    WriteLine("{hello} {world}", hello => "Hello", world => "World!");
}

public static void WriteLine(string format, params Func<object, object>[] args)
{    
    Console.WriteLine(Hash.Format(format, args));
}

As Jeremy Skinner puts it, “By taking an array of delegates, it is possible to capture the compile-time variable names used by the lambda expressions and use them as keys for the dictionary.”

There are a couple of problems with doing this. Making the variable name of the lambda expression have implications runs counter to the standard implementation of lambda expressions. It is possible for someone to refactor your code and not realize that changing the variable name will break the the program’s functionality. Another problem is that every usage of this is tied to the Hash class of a third party library. It would be better if the desired functionality had actual language support.

One other thing I recommended in here was a type keyword, dict, for IDictionary. That’s only because I can imagine it would get long typing params IDictionary<object, object> every time.

Changes for this would require some compiler work, but I believe it would make the C# language stronger. There are more uses for it than formatting string: just about any time you need a dictionary you could use it. Hopefully this will make it into C# 5, but it only will if you ask the C# team for it. Blog about it, ask about it in the forums, demand and end to the lambda abuse!

In the meantime, if you want a solution for string formatting with named variables, check out James Newton-King’s article. He does it with anonymous types.

Bookmark and Share

Null Coalescing Assignment Operator for C# 5

by KodefuGuru 7. January 2010 16:53

If you read my article on the null coalescing operator (??), you’ve probably got a good idea on how useful it is. It makes your code more declarative, which makes it easier to read. But I find one thing disappointing about it, which I hope can be corrected in C# 5 with the introduction of a new operator.

One way to use the null coalescing operator is by checking a variable against itself, and if it’s null assign another value. Besides eliminating imperative code, this is great when combined with factory methods.

client.WorkOrder = client.WorkOrder ?? WorkOrder.Create();

My complaint is that you have to declare the same value on the left and right side. It’s not much, but it’s easily corrected. Due to C#’s C-based heritage, other types of assignment operators, called compound assignment operators, already exist: +=, –+, *=, /=, %=, &=, |=, ^=, <<=, and >>=. These work as if you had broken them apart. In other words, x += y is the same as x = x + y. There are two differences: the left operand isn’t repeated and the C# compiler evaluates the left operand once with the compound assignment operator.

I propose a new compound operator for C# 5: the null coalescing operator. The symbol for it would logically be ??=. It will simplify our code when working in a declarative manner.

client.WorkOrder ??= WorkOrder.Create();

It doesn’t require a framework change as the IL generated by compound assignment operators is the same as their analogues. It’s a compiler change, and I don’t believe it would be a difficult one at that.

Bookmark and Share

Binding Operators for C# 5

by KodefuGuru 3. December 2009 11:56

I read this article from Martin Calsyn on the new Microsoft Visualization Language called Vedea, and I must admit that I was struck by how awesome binding operators actually are. This is a feature that must make its way into C# 5! Here’s an example of a binding from his article.

textbox.Text := slider.Value;

This code looks suspiciously like Delphi. In Pascal (Delphi uses Object Pascal), := is an assignment operator. In Videa, := is a left binding assignment. What happens is that anytime the slider’s Value property is changed, the textbox.Text property updates to reflect that change.

textbox.Text :=: slider.Value;

The :=: operator is a two-way binding operator. Now, if the textbox.Text property is modified, slider.Value is changed as well.

Martin then shows just how powerful these bindings are.

myData = DataSet(“mydata.csv”); 
currentYear := slider.Value + 1900; 
bubbles := from row in myData  
  where row.Year :== currentYear  
  select new Circle()  
    {  
      X = row.Latitude,  
      Y = row.Longitude,  
      Radius = row.Population * scalingFactor,  
      Fill = BlackBodyPalette(1., 1., row.DeltaCarbon)  
    }; 
Scene[“USMap”].Add(bubbles);

This code loads data from a CSV file (similar to Jim Wooley’s LINQ to CSV) and assigns it to the myData variable. It then binds the slider.Value + 1900 to the currentYear variable; this will be used in our LINQ binding. Then a query on the data is bound to the bubbles variable which is used to show bubbles on a map. Inside of the LINQ statement, there is a boolean binding operator, :==, which assigns currentYear to the row.Year. This combines to have the powerful effect of changing the bubbles on the map to reflect the data in the CSV whenever you move the slider.

As you can see, this code is extremely powerful. It was made possible by the introduction of the DLR into the .NET framework. Kudos to the Microsoft Research team in Cambridge, UK for making such an awesome language. Now please make sure it makes its way into C# 5!

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
C# MVP, INETA Community Champion


MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er

I have joined Anti-IF Campaign


World Map

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010