Tuesday, 11 August 2009
Expression as a Compiler
Monday, 22 June 2009
Using Expression when creating runtime types
Over the weekend, I've been looking in more depth at the DLR trees in 4.0 (beta) - and an interesting little nugget leapt out at me... you can now compile an expression tree into the body of a MethodBuilder! This means that even when writing a full type at runtime you can write the methods using an object model rather than Reflection.Emit.
My current example of this doesn't really illuminate much, so I won't post it "as is" - probably to follow. But does this sound "time" for people having to learn how to use ILGenerator?
Don't get me wrong - expression trees aren't trivial, and you need to think carefully when writing them - but they are a lot simpler than writing IL directly.
Wednesday, 27 May 2009
Exploring 4.0; Expression and Dynamic
class Foo
{
public string Bar { get; set; }
public override string ToString()
{
return Bar;
}
}
static void Main()
{
var param = Expression.Parameter(typeof(Foo), "foo");
var assign = Expression.Assign(
Expression.Property(param, "Bar"),
Expression.Constant("def", typeof(string)));
var writeLine = Expression.Call(
typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }),
param);
var action = Expression.Lambda<Action<Foo>>(Expression.Block(assign, writeLine), param);
var actionDel = action.Compile();
Foo foo = new Foo();
actionDel(foo);
}
int
Operator: 833ms (100000010)
Dynamic: 1383ms (100000010)
float
Operator: 786ms (3.355443E+07)
Dynamic: 1309ms (3.355443E+07)
decimal
Operator: 3974ms (100000010)
Dynamic: 3911ms (100000010)
Wednesday, 8 April 2009
Re-implementing Expression for Compact Framework
ProtoClient<IMyService> client = ...
double amount = client.Invoke(svc => svc.DoSomeMaths(
12, someObj.Qty));
- a lambda that accepts parameters
- that can invoke methods
- that can use constant argument values
- that can use properties and fields as values
- that can use captured values (which are implemented as fields)
double amount = client.Invoke(svc => svc.DoSomeMaths(
12, someObj.Qty * 2));
int qty = someObj.Qty * 2;
double amount = client.Invoke(svc => svc.DoSomeMaths(
12, qty));
- Expression.Constant
- Expression.Parameter
- Expression.Field
- Expression.Property
- Expression.MethodCall
- Expression.Lambda<T>
Thursday, 19 March 2009
Visualizing Expressions in PropertyGrid
The problem
The Expression API is complex; not least because picking apart an Expression is complicated. For example, lets pick an expression that removes the first and last characters from a string:
s => s.Length > 2 ? s.Substring(1, s.Length - 2) : s;
If you are working regularly with Expression, you often need to be able to visualize it (if only to stay sane); this counts doubly if we want to understand how to construct our own Expression to do something similar. Ideally without needing any external tools / plug-ins, and something a bit more permanent than the inspector in the IDE.
If you wanted to write down what that actually means (which is what Expression has to do):
- given a parameter "s"
- branch by evaluating the greater-than operator with arguments:
- query the Length of "s"
- the constant 2
- if true, evaluate Substring on the parameter "s" with arguments:
- the constant 1
- the result of the subtraction operator with arguments:
- query the Length of "s"
- the constant 2
- if false, evaluate the parameter "s"
- branch by evaluating the greater-than operator with arguments:
Although fairly mechanical, pulling apart Expressions can take time. If only the system could display it for us.
The naïve approach
But wait a minute! PropertyGrid is good at displaying tree-like data - lets try setting the SelectedObject to an instance of the above Expression:
Disappointed? It doesn't really help us (and note that the Parameters collection is not expandable). The problem is that PropertyGrid uses TypeDescriptor (and friends) to query the metadata, and Expression simply isn't configured to allow hierarchical browsing. But what many people don't realise is that TypeDescriptor allows runtime configuration.
Changing the type-converter
Behind the scenes, PropertyGrid uses the TypeConverter associated with a type (or an individual member), by querying GetPropertiesSupported(), and (if it returns true) GetProperties(). And even better, there is an inbuilt converter (ExpandableObjectConverter) that exposes all the public members for nested browsing.
Additionally, TypeDescriptor offers an indirect way to associate a different type-converter with a type; by adding an attribute at runtime*. Since Expression is the base class for all the interesting objects in the Expression API, we only have to tweak this one type:
TypeDescriptor.AddAttributes(typeof(Expression),
new TypeConverterAttribute(typeof(ExpandableObjectConverter)));
This is broadly equivalent to using the attribute at compile-time:
[TypeDescriptor(typeof(ExpandableObjectConverter))]
public abstract class Expression { /* ... */ }
*=for the pedants (myself included), I should note that we only add an attribute to the runtime model (System.ComponentModel); reflection is unaware of this change.
What does it look like now?
So how much difference does that one line make? Test again, and we see something very different - both in the main grid, and in the collection pop-ups:
So with just 1 line of code, we've obtained a free tool for exploring Expression; I'm not saying it is the prettiest tool ever, but it is plenty good enough, considering that the main audience would be you, the developer.
It begs the question; why isn't it expandable in the first place?
Sunday, 15 March 2009
Explaining Expression
- The delegate version (Func<int,int,bool>) is the beligerant manager; "I need you to give me a way to get from 2 integers to a bool; I don't care how - when I'm ready, I'll ask you - and you can tell me the answer".
- The expression version (Expr<Func<int,int,bool>>) is the dutiful analyst; "I need you to explain to me - if I gave you 2 integers, how would you go about giving me a bool?"
Wednesday, 11 March 2009
Back to the coal face
- It is no secret that the big theme in .NET 4.0 is the DLR; despite some C# dabbling (here, here), I need to get my head around this "proper"... to that end, I've secured a copy of IronPython in Action, which I hope will set me on the one true path. Besides which - it is good to look at other languages occasionally (and I never really got far with F#).
- It is no secret that there are lots of changes afoot with Entity Framework and ADO.NET Data Services; now that I've had chance to see them, I'm encouraged that they might be a lot more usable in 4.0 - still waiting on the "bits" though ;-p
- Windows 7 continues to look very good; I've got the beta at home, and it runs very well on my ancient machine - and the newer builds look even better. Microsoft stand a good chance of actually getting some forgiveness for Vista.
- The EMP is very, very... odd. Beer, a live-rock/karaoke, an Xbox Rock Band arena and a robot museum all in one.
Friday, 20 February 2009
Pragmatic LINQ
LINQ, especially when talking to a database (or other back-end), arguably creates a bit of a tricky mess for proper application design.
Consider:
- I'm strongly in favour of proper unit testing
- As such, I like the repository pattern, since this allows me to mock my DAL
- In reality, I don't really need true POCO support; if I start needing my app to work with MySQL, I have bigger problems than POCO
- I like that LINQ-to-SQL / EF can maintain a basic object model for me
- Since it doesn't buy me anything, I don't really want to declare and maintain a "pure" (i.e. separate to the DAL) object model - I'm generally content to use partial classes to extend the classes we have generated
- For use in things like MVC, I want to know when data access happens; I don't want my view messing with lazy navigation properties
- I'm content (at the minute) to have a DAL that includes the LINQ-generated classes, the repository interface, and a class implementing that interafce, and think of it as "my object model assembly that happens (by coincidence) to contain a default repository implementation" (try saying that twice...)
- While I'm happy to know that LINQ to SQL supports POCO usage, the tooling doesn't make it easy. For now, I'm content to use attributed classes, and get on with the job...
So what?
Well, the first impact this has is: if you want it to be testable in any real sense, there isn't a lot of the LINQ stuff that can make it into the public API. For example:
- the data-context - has nothing to do with external callers in a repository implementation
- navigation properties - very quickly start crossing aggregates and/or causing lazy behaviour (not good if your context no longer exists)
My current thinking with this is that the data-context and most navigation properties should be marked as internal to the data layer (trivial either in the designer or dbml views). This means that your repository implementation can use the navigation properties to construct interesting queries, but the public API surfaced back to the caller doesn't include them. If the caller gets and order from the order repository, and wants details about the customer: tough - go and ask the customer repository. There is an edge-case for tightly coupled data (order header/details being a prime example), where it might be prudent to leave the navigation property public - but this is in the same aggregate, so this isn't a problem.
It isn't whiter than white - but it seems pretty workable:
- The repository interface protects our data-context from abuse; we know what use-cases we are supporting, and that they have been tested
- The lack of navigation properties means we know when data access happens : it is when the caller asks the repository
The bit where I'm a bit mixed is in the subject of allowing the caller to use Expression arguments on method calls; the ability to pass in an Expression<T,bool>-based predicate is powerful, but risky: we can't validate that our DAL covers all use cases (due to unmapped method calls etc), and we can't be 100% what TSQL is going to execute in reality (even small composed expressions can radically change the TSQL expression). I think I'd need to evaluate that on a need-by-need basis.
I don't know if I'm saying anything a: obvious, or b: stupid... but that is my thinking...
Tuesday, 4 November 2008
Future Expressions
Last post, I looked at what Expression offered in C# 3.5; to re-cap, very versatile at building simple queries, but not useful for writing manipulation code - in particular, the only in-built assignment is via Expression.MemberInit etc, which is useful only when creating new objects - or at a push you can perform a single update by obtaining the setter and using Expression.Call.
The interesting news is that this looks very different in .NET 4.0 (based on the public October 2008 CTP). It appears that Expression underpins much of the DLR / dynamic work - so there are all sorts of interesting new options - essentially, Expression is the new CodeDOM... personally I am very excited about this; I've always found Expression a far more intuitive and workable abstraction than the counterparts.
In .NET 3.5, there are 46 values in the ExpressionType enum; in .NET 4.0 (CTP), this jumps to 69, with options for loop constructs (loop/dowhile/break/continue/yield), member assignment, composite statements (block/comma?), and exception handling.
The new entries (again, based on the CTP) are:
- ActionExpression
- Assign
- Block
- BreakStatement
- Generator
- ContinueStatement
- Delete
- DoStatement
- EmptyStatement
- Extension
- IndexedProperty
- LabeledStatement
- LocalScope
- LoopStatement
- OnesComplement
- ReturnStatement
- Scope
- SwitchStatement
- ThrowStatement
- TryStatement
- Unbox
- Variable
- YieldStatement
I won't pretend to understand them much yet, but I will be investigating! I also understand that the C# 4.0 compiler doesn't support expressions with statement bodies at the moment (although you can build things by hand - which isn't trivial). It will be interesting to see if this changes (not least because reflector is such a good tool for discovering how you are meant to construct these expressions!).
[update] As an example, I previously gave the example of something you can't do in .NET 3.5:
Expression<Action<Foo>> action = foo =>
{
foo.Bar = "def";
Console.WriteLine(foo);
};
Well, here it is in .NET 4.0:
class Foo
{
public string Bar { get; set; }
public override string ToString()
{
return Bar;
}
}
static void Main()
{
var param = Expression.Parameter(typeof(Foo), "foo");
var assign = Expression.AssignProperty(
param,
typeof(Foo).GetProperty("Bar"),
Expression.Constant("def", typeof(string)));
var writeLine = Expression.Call(
typeof(Console).GetMethod("WriteLine", new[] { typeof(object) }),
param);
var action = Expression.Lambda<Action<Foo>>(Expression.Comma(assign, writeLine), param);
var actionDel = action.Compile();
Foo foo = new Foo();
actionDel(foo);
}
And of course, there are obvious issues with existing LINQ implementations: if you use some of the new constructs, you should expect your legacy LINQ provider to barf; and indeed, most of the new options simply don't make sense for a database call, so we shouldn't expect too much to change in LINQ-to-SQL/EF.
Monday, 20 October 2008
Express yourself
I thought I'd start by having a look at expressions - in particular System.Linq.Expressions.Expression.
Expression is an important part of the glue that makes LINQ work, but it has been almost completely hidden away by the spectacular job that C# 3.0 makes of lambda statements and LINQ.
For example, consider the following C# 3.0 query:
var qry = from foo in source
where foo.Bar == "abc"
select foo;
Because of how query syntax is interpreted, this is identical to the following:
var qry = source.Where(foo => foo.Bar == "abc"); // Sample A
But what does this mean? Well, first it depends on what our "source" is, or more accurately, whether our Where() method accepts a delegate or an expression tree. For LINQ-to-Objects, then the Where will accept a delegate (such as Func<T, bool>), and so (keeping the extension method syntax) this is identical to:
var qry = source.Where(delegate(Foo foo) {
return foo.Bar == "abc"; });However, for most other LINQ providers, it is likely that the Where method accepts an expression tree instead (such as Expression<Func<T,bool>>). So what is an expression tree? The short and imprecise answer is that is is an object representation of code - similar in some (very limited) ways to things like CodeDom - but aimed squarely at providing LINQ support - i.e. all the operations you might need for every-day queries, and the ability to point to framework methods for things that can't be expressed purely in expressions.
Doing It The Hard Way
So lets dissect our example: looking at the delegate version, you can see that the function (the argument to Where) accepts an argument called "foo" (of type Foo), performs member-access (.Bar), and performs an equality test with the string constant "abc". So lets try writing that (as an expression) ourselves:
ParameterExpression foo = Expression.Parameter(typeof(Foo), "foo");
MemberExpression bar = Expression.PropertyOrField(foo, "Bar");
ConstantExpression abc = Expression.Constant("abc", typeof(string));
BinaryExpression test = Expression.Equal(bar, abc);
Expression<Func<Foo, bool>> lambda =
Expression.Lambda<Func<Foo, bool>>( test, foo);
var qry = source.Where(lambda);
Yikes! That looks like a lot of work! And you'd be right... but take it step-by-step and it makes sense:
- We declare a parameter "foo" of type Foo
- We perform member-access to get foo.Bar
- We define a string constant "abc"
- We test the value of .Bar against this constant
- Finally, we wrap the whole thing up in a lambda; this is just our way of baking the expression into something usable (and note that we need to explicitly re-state the parameter we expect).
Doing It The Easy Way
The good news is that in most cases, we simply don't need to do any of this; the compiler does all the hard work for us; in fact, it can use a number of tricks that can't be done conveniently in regular C#, such as pointing directly at a MethodInfo for the "get" (.Bar); here's what reflector shows for our original "Sample A":
ParameterExpression CS$0$0000;
IQueryable<Foo> qry = source.Where<Foo>(Expression.Lambda<Func<Foo, bool>>(Expression.Equal(Expression.Property(CS$0$0000 = Expression.Parameter(typeof(Foo), "foo"), (MethodInfo) methodof(Foo.get_Bar)), Expression.Constant("abc", typeof(string)), false, (MethodInfo) methodof(string.op_Equality)), new ParameterExpression[] { CS$0$0000 }));
OK, that isn't the easiest code to read... it is mainly the same as our previous example (but with explicit generics and "params" values). The parameter usage (CS$0$0000) looks tricky, but is still the same - just initialised and used in the same code block.
The two big differences are in how ".Bar" and "==" are performed; note the use of "methodof(Foo.get_Bar)" and "methodof(string.op_Equality)". No, this isn't a C# keyword you didn't know about - it is simply reflector doing the best job it can of displaying something that isn't valid C#, but is valid IL - using a MethodInfo directly instead of via reflection. In our hand-cranked version, the Expression API will get the same answer, but needs to jump through a few more hoops first.
So Why Bother?
It would be valid, at this point, to ask: "If the compiler can write expressions for me, and do it better, why should I care?". And in most day-to-day coding you would be right: please don't start re-writing your LINQ queries with hand-cranked expressions! And in particular, they are pretty-much a nightmare to use (manually) with anonymous types. However, they do have some intersting possibilities. For regular LINQ (even LINQ-to-Objects via .AsQueryable()), this can be useful for things like:
- Dynamic filters / sorts / etc based on properties that cannot be known at compile-time
- General expression-tree manipulation: merging trees (at InvocationExpression nodes), re-forming trees, etc
But for me, a more common-place usage is in using expressions as the basis of a micro-compiler: a hidden gem of an Expression<T> is the Compile() method; this lets us turn our lambda into a typed delegate, ready for use. But this isn't using reflection (when executed): it creates regular IL in a dynamic assembly that can be invoked very efficiently. This is as simple as:
Func<Foo, bool> predicate = lambda.Compile();
Foo obj = new Foo { Bar = "abc" };
bool isAbc = predicate(obj);
Now, obviously there is some cost to this:
- we need to build an expression tree (with the reflection lookups etc)
- the library code needs to parse the expression tree (including validation), and emit IL
So this isn't something we'd want to do every time we call the method - but stick the delegate creation in some start-up code (perhaps in a static constructor / type initializer, storing it in a static readonly field) and you have a powerful tool.
So What Can We Do?
So far, I've only given a very small glimpse of the expression capabilities available, but the list is quite comprehensive, with no fewer than 60 different methods. This covers most of the common things you want to do, including:
- all common operators
- branching (conditional)
- object construction
- collection / array construction
- member access
- invocation (to both regular .NET methods and to pre-existing lambda expressions)
- casting / conversion
The biggest thing to note is that expression-trees are designed to encapsulate a functional statement; in particular:
- it doesn't lend itself to mutating existing instances
- it doesn't lend itself to writing a series of statements (unless you can chain them via a fluent API or an operator such as +)
- it should return something (i.e. not Action<T>)
What I mean is that you can't write the following (either in C# or manually):
Expression<Action<Foo>> action = foo =>
{
foo.Bar = "def";
Console.WriteLine(foo);
};
since it fails all 3 conditions.
Example
So far, I've just tried to give a flavor of what you can do with expression trees. I've covered some more of this in various places, that might be interesting:
- Generic operators [overview | usage] - i.e. +-/* with generic T; this is used in MiscUtil as part of the Push LINQ code
- Object cloning [here] - efficient object cloning without the pain
- LINQ object construction [here]
- Partial LINQ projections [here]