Constraining generic constraints 1

Posted by Jb Evain Fri, 13 Jan 2012 13:30:00 GMT

This is the last part of an update about Mono.Linq.Expressions, a tiny helper library to complement the System.Linq.Expressions namespace for .net 4 and Mono.

And it's not really about Mono.Linq.Expressions itself. If you're interested about it though, you can read the part about fluently creating expression trees, and the other one about combining lambda expressions together.

Proper generic constraints


Have a look at the signature of the factory method Expression.Lambda:

public static Expression<TDelegate> Lambda<TDelegate> (
    Expression body,
    params ParameterExpression [] parameters) {}

And at the signature of Expression<T>:

public sealed class Expression<T> : LambdaExpression {}

Given the post title, and the <h3> a few lines up there, it's obvious where I'm going: those generic parameters have no constraint. A C# compiler will happily compile:

class Potato {}

Expression<Potato> e = Expression.Lambda<Potato> (
    Expression.Constant (new Potato ()));

Of course this won't get you far, but it sure is a heart breaker that because of a little language oddity, you delay to until runtime the problem resolution: this code will throw, Potato sure isn't a Delegate type, and Expression.Lambda, the only way to create an Expression<T> is making sure of that.

So much for type safety, generics!

Another famous issue is the following. Again, for the compiler, it's perfectly legit to write:

int i;
if (!Enum.TryParse ("42", out i))
    Console.WriteLine ("This is so unfair!");

And why is that? Because of the signature of Enum.TryParse:

public static bool TryParse<TEnum> (string value, out TEnum result) where TEnum : struct {}

To sum the issue up, C# doesn't allow generic constraints on delegates and enums. And why am I rumbling about this? Because Mono.Linq.Expressions has this method:

public static Expression<T> Combine<T> (
    this Expression<T> self,
    Func<Expression, Expression> combinator)

And if Expression<T> is not constrained on Delegate, then I sure as hell won't let this stand in my own public API! Which is why the actual signature of the Combine method is:

public static Expression<T> Combine<[DelegateConstraint] T> (
    this Expression<T> self,
    Func<Expression, Expression> combinator) where T : class

And all of this was just a perfect excuse to write a little Mono.Cecil based utility tool, appropriately named patch-constraints, that is used as a post-compile step to fixup the Delegate and Enum constraints of any generic parameter decorated respectively with a DelegateConstraintAttribute or EnumConstraintAttribute, turning them into actual constraints to delegates and enums, which, funnily enough, the C# compiler is more than happy to honor.

Obviously I could have used the most famous Jon Skeet's unconstrained-melody tool, but 2002 called and it wants its ildasm based, IL text parser back.

Mono.Linq.Expressions update 2

Posted by Jb Evain Thu, 12 Jan 2012 11:25:00 GMT

This is the second part of an update about Mono.Linq.Expressions, a tiny helper library to complement the System.Linq.Expressions namespace for .net 4 and Mono.

The first part is about fluent creation of expression trees.

Combining expression trees together


I keep reading questions on StackOverflow about this. How to combine two lambda expression together? If we have:

Expression<Func<User, bool>> isUserOver18 = u => u.Age >= 18;
Expression<Func<User, bool>> isFemaleUser = u => u.Gender == Gender.Female;

If we want to combine this lambda expression with a “and” logical expression, the natural way would be to write:

Expression<Func<User, bool>> isFemaleUserOver18 = u =>
    isUserOver18(u) && isFemaleUser(u);

This works just fine if you compile the expression into a delegate to actually execute this code. But most of the time questions of StackOverflow are about using the resulting lambda expression to create a query for LINQ to a database provider, which will analyze the expression tree and create an according SQL request.

By combining expression trees this way, the LINQ provider may or may not be unable to turn the two invocations into actual SQL.

That's one of the reason I wrote about an updated PredicateBuilder. The obvious solution is to inline the two combined representation of lambda expressions into a new lambda expression tree.

The update of Mono.Linq.Expressions comes with a new type, CombineExtensions, which exposes extension methods that you can use to combine fully created (into lambda expressions) expression trees.

Using those, combining the two expression trees is as simple as:

Expression<Func<User, bool>> isFemaleUserOver18 = isUserOver18.Combine(
    isFemaleUser,
    (left, right) => left.AndAlso(right));

And indeed, if you print the code representation of this expression tree, you'll have both lambda bodies inlined into another one:

user => user.Age >= 18 && user.Gender == Gender.Female

Or if you want to negate the boolean expression:

Expression<Func<User, bool>> isNotFemaleUserOver18 = isFemaleUserOver18.Combine(
    e => e.Not());

The cool thing about those Combine extension methods is that they're completely generic, they don't work only on simple predicates. For instance, you can use those to chain constructions of mathematical expressions.

Mono.Linq.Expressions update 2

Posted by Jb Evain Wed, 11 Jan 2012 16:00:00 GMT

I just tagged the 1.2 version of Mono.Linq.Expressions, and pushed an updated nuget package.

Mono.Linq.Expressions is a utility library to complement the System.Linq.Expressions namespace, and works with .net 4.0 just as fine as it does with Mono. With a bit over 220 downloads of the nuget package, it's short of roughly 160,400 downloads to be the most downloaded nuget package : a stunning success to put it simply.

This post is the first of a short series to detail what's awesome and new in this version.

Extension methods for a fluent construction of expression trees.


Have you been using the expression tree API to build a representation of code at runtime ? If so you're familiar with the Expression class, and it's load of factory methods.

You're also familiar with this kind of code:

var user = Expression.Parameter(typeof (User), "user");

var isFemaleUserOver18 = Expression.Lambda<Func<User, bool>>(
    Expression.AndAlso(
        Expression.GreaterThanOrEqual(
            Expression.Property(user, "Age"),
            Expression.Constant(18)),
        Expression.Equal(
            Expression.Property(user, "Gender"),
            Expression.Constant(Gender.Female))), user);

If you take some time to parse this code, the intent is to create an expression tree similar to the one the compiler would emit if you were to write:

Expression<Func<User, bool>> isFemaleUserOver18 =
    user => user.Age >= 18 && user.Gender == Gender.Female;

Mono.Linq.Expressions 1.2 contains a code generated series of extension methods to simplify the manual construction of expression trees by fluently chaining the invocations. This allows you to write instead:

var user = typeof (User).Parameter("user");

var isFemaleUserOver18 = Expression.Lambda<Func<User, bool>>(
    user.Property("Age").GreaterThanOrEqual(18.Constant())
    .AndAlso(
        user.Property("Gender").Equal(Gender.Female.Constant())), user);

Not only is the code shorter, but it's also easier on the eyes, and easier to comprehend. Using this, almost the factory methods calls to the Expression class can be written fluently.

TechDays 2011

Posted by Jb Evain Mon, 07 Feb 2011 22:01:00 GMT

Mercredi, j’aurai l’opportunité de présenter Mono et son écosystème pendant les TechDays Microsoft.

Ce sera l’occasion de faire le point sur les dernières nouveautés de Mono, et de montrer comment réutiliser ses compétences .net et partager son code C# pour cibler des plateformes en vogue, comme l’iPhone et l’iPad avec MonoTouch, Android avec MonoDroid et Mac OS X avec MonoMac.

Si vous ne pouvez pas assister à la session, je serai aussi disponible sur le stand alt.net pour discuter de tous ces sujets. Venez nombreux !

Older posts: 1 2 3 ... 17