Having fun with Linq to Nullable types

In C#, the following function compiles:

static double? Add(double? x, double? y) 
{
     return x + y; 
}


Even though there is no addition operator defined for double?, or for Nullable<T> in general. But the C# compiler translates the above to:

static double? Add(double? x, double? y) 
{
    return x.HasValue && y.HasValue ? new double?(x.GetValueOrDefault() + y.GetValueOrDefault()) : null; 
}


But I cannot write the following:

static double? Abs(double? x) 
{
     return Math.Abs(x); // won't compile 
}


With a bit of Linq though, I can write the following:

static double? Abs(double? x) 
{
     return from d in x select Math.Abs(d); 
}


All I need to make this work is the following extension method:

public static T? Select<T>(this T? x, Func<T, T> selector)
     where T : struct 
{
     return x.HasValue ? new T?(selector(x.Value)) : null; 
}


I could even add a Where extension method:

public static T? Where<T>(this T? source, Func<T, bool> predicate)
     where T : struct 
{
     return source.HasValue && predicate(source.Value) ? source : null; 
}


Which would allow weird (or cool?) stuff such as:

static double? Asin(double? x) 
{
     return from d in x where d >= -1 && d <= 1 select Math.Asin(d); 
}


Toss in a SelectMany:

public static V? SelectMany<T, U, V>(this T? source, Func<T, U?> k, Func<T, U, V> resultSelector)
     where T : struct
     where U : struct
     where V : struct 
{
     if (k == null)
     {
         throw new ArgumentNullException("k");
     }
     if (resultSelector == null)
     {
         throw new ArgumentNullException("resultSelector");
     }
     return source.HasValue && k(source.Value).HasValue ?
          new V?(resultSelector(source.Value, k(source.Value).Value)) : null; 
}


And now I can write:

static double? SinCos(double? x, double? y) 
{
     return from xd in x
            from yd in y
            select Math.Sin(xd) * Math.Cos(yd); 
}


Who said Linq was about object-relational mappers? Or was it functional programming perhaps?

Technorati tags: , , ,