Sunday, October 11, 2009

Follow up for meeting regarding Iterators/Ranges

We were looking at the examples Jon gives in his chapter on iterators, especially his take on ranges.
We had a hard time understanding the code of the GetEnumerator code:

image
Why these two constructs? And why using CompareTo directly?
Lets look at the second question first! Basically what the GetEnumerator method should do is yielding a new value and “incrementing” the value as long as the value is contained in the range. But the original code in the example behaves slightly differently. When you look at it a little bit closer you’ll notice the loop will only terminate when the value is equal or greater then the end value of the range. This assumes that the values will be increasing all of the time. But if the values are decreasing the values will always be less than the end of the range: We have an infinite loop. And what’s more we get values that will not return true when provided as an argument to the Contains method of the object that produced the value in the first place.
A simple test reveals this fact:
image
which gets us this test result:
image
If we simply change the code to use the Contains method the Range<T> class already provides the class will behave as expected.
Here is the modified version:
image
This is not only working correctly even for step values that will result in decreasing results of GetNextValue but it is much easier to understand.
There is one thing that is to say for the original code: It runs faster. To check that I changed to code of the GetEnumerator to use either the original or the modified code.
image
I will just use a static variable in the Switcher class to either use the original (Jon’s) code or the modified version. The following performance test
image
creates a range of 50 million integers and iterates over them using the GetEnumerator method and outputs the switch settings, the elapsed time, the ticks per iteration and finally a comparison of the performance between the original and the modified code. Here is the result:
image

Wednesday, July 8, 2009

Summary for Meeting 3: Nullables<T>

Summary for Meeting 3: Nullables<T>

This is a rather short chapter and we didn’t expect very much new information. But as always when you start to look at things and start to explain them to each other interesting points pop up.

  • I was not aware of the GetValueOrDefault method on Nullable<T>. Never used it.
  • Boxing/Unboxing of Nullables: 4.2.2 pp 118, 119: I had no idea that this might be an issue. But that boxing an instance of Nullable<T> results in either a null reference or a boxed value of the underlying type does make perfect sense.
  • The class Nullable. Never used it as well. But I should have used the GetUnderlyingType method. I firmly believe that I have implemented exactly that feature two or three times in the last couple of years in various projects using reflection.
  • Then we wondered why one would need the static class Nullable with its Compare and Equals method. We first thought (actually I did and I was completely wrong) that when using the instance method Equals of a concrete Nullable<T> instance it would throw a NullReferenceException when the instance had no value. But as Nullable<T> is a value type and not a reference type it in itself can never be null and it handles the case described without any problems.
    The Nullable static class just delegates the main work to the objects returned by Comparer<T>.Default and EqualityComparer<T>.Default (where T is the underlying type of the Nullable) in the cases that both have instances have a value and dealing with the case that one or the other or even both of them are null.
  • No surprise for me personally about the null coalescing operator. But as Jon Skeet states in his book, I notice that it is one of the lesser known features of C#. My estimation is that 2 out of 3 developers do not know it. (As an anecdote I had a code review with an architect and had to explain that operator to him). Even though I used it for years I never thought of the inventive ideas that Jon Skeet explains. Have a look further down down in this post for more on the null coalescing operator.
  • Using Nullable<T> for trying an operation: That idea is brilliant. Why didn't I think of it? I used it right away. The main point that instead of using a method with a Boolean return value and a out parameter for the result (like int.TryParse) you return a Nullable<T> and if the operation succeeded you return a Nullable<T> with the value you are interested in. If the operation did not succeed,  you return null.

 

Here are some further remarks on the null coalescing operator.

Null coalescing operator with objects of various types

The first scenario is out of the GUI lay of an application I am just working on. Lets say we need to find out if a drag and drop operation is possible.  One idea was to write code like the following:

User u = someObject as User;
Role r = someObject as Role;
Title t = someObject as Title;

// won’t work!
object o = u ?? r ?? t;

if (o != null) PerformDragDropAction();

As indicated by the comment, this will not work. The null coalescing operator is not very happy if it is applied on variables of different types.

As it turns out casting the last variable to object will be accepted by the compiler.

// but this works
object o = u ?? r ?? (object)t;

You can even cast the next to last variable used in the chain of operators..

// this as well, but it’s even uglier
object o = u ?? (object)r ?? t;

Null coalescing operator for very short property initializers

One thing that I find very unpleasant is the lazy initialization of property values.

What you usually write is something like this (and yes I know: When you are using an IoC container, you are very unlikely to write such code)

private ILogger logger;
public ILogger Logger

    get 
    { 
        if (logger == null)
        {
            logger = new Logger();
        }
        return logger; 
    }
}

But you can do it with very little code in this way:

private ILogger logger;
public ILogger Logger
{
    get { return logger ?? (logger = new Logger()); }
}

This works, because the result of an assignment seems to be the assigned value.

This code is very short. Its main problem is the fact that it is not as idiomatic as the first, longer version. Most people will take much longer to comprehend what is going on when reading the second version in comparison to the first.

Friday, May 29, 2009

Next meeting scheduled for 18.06.

As I'll be on holiday, we discuss Chapter 3 after my return on the 18th of June.

Edit: Forgot my notes at home - moved meeting to Monday 22nd of June.
Edit: Now Ralf has timing problems - moved meeting to Wednesday 24th of June.

Tuesday, May 26, 2009

First Session

Yesterday we had the first session of our study group. We prepared Chapter two of the book, and discussed items that seemed especially of interest, surprising or unclear for at least one of the group.
Not very surprisingly, few things were unclear, as it was a detailed refresher of basic parts of C# 1.
Still, for me as a beginner in C# (still less than four months of experience), I got a lot out of the book as well as the discussion.
Some were minor points, as the aggregation of delegates and also their immutability. Furthermore that delegates prevent garbage collection of the instance (if delegate instances) is pretty obvious, but previously it never occured to me.

A surprise to me was (as I never started with C# 1), that covariance and contravariance was a problem when dealing with delegates (signature had to be exactly the same). When discussing this, we also had to clarify the meaning of the words covariance and contravariance.
In simple words: covariance is "cast" to a more general object, contravariance to a more specific.
I.e. a cast from string to object would be covariant, object to string contravariant.

When talking about Extensions (which were new to me), we discovered that the usage of the string type is not completely intuitive to us. Methods like string.Format() are not usable like "hello {0}".Format("world"); The reason we came to this was that you could provide this behavior in writing an Extension for string.

When talking about the handling of strings, we also came to the discussion, if a parameter of a method is a string, sometimes you check it for null and emptyness.
You could throw two different, separate exceptions for this. Our feeling was though, that this would increase work, without really giving anyone that much information. If a string that is null or empty produces an exception the information whether it is null or empty is not that crucial. Although my feeling is that there are people who might not concur.

Thursday, May 14, 2009

First Study Group meeting Monday, 25th May

So the first meeting is scheduled.
Right now we plan to go through the book chapter by chapter.

Let's see how it will turn out.