Wednesday 29 April 2009

Handy editor tweaks with SlickEdit Gadgets

I'm fairly conservative when it comes to additional IDE add-ins (Visual Studio has enough going on without throwing in the kitchen sink), but I came across a very interesting little library the other day; SlickEdit Gadgets - and just have to share. Best done with an image:

SlickEdit Gadgets showing a line ruler, indentation guide, and editor graphic

What we can see here is:

  • an "indentation guide" (the vertical dashed line) - very handy for "at a glance" indentation checks - which (if your code follows any kind of convention) means that you can also get an immediate clue to the nesting of the current line. Much easier than trying to brace highlighting, or the confusing mess of lines that some tools insert - just move to the line you are interested in, and "presto".
  • a "line ruler" (the horizontal highlight) - again, tied to the current line, but giving a very visual cue where we are. Much easier than trying to play "hunt the caret" (which is not a euphemism). In particular, I see this as being useful for anyone doing pair/team programming, or giving presentations - no more mouse-waggling / laser-pointer-tag trying to indicate a specific line.
  • an "editor graphic" (the coffee cup) - an image of your choice right there in the editor window... maybe not hugely desirable on a day-to-day basis, but maybe a sweet gimmick when giving external presentations - perhaps put the user-group's / code-camp's logo up there as a reminder. Or not ;-p

As you might expect, there are suitable options for styling (colour, animation, etc). There are a few other tools too (not shown) - including an in-IDE file explorer, automatic "copy", a tool for sniffing the IDE commands, etc.

But most importantly, these tools are freely available.

I also intend to take a look at their actual Visual Studio products at some point - the Editing Toolbox / Versioning Toolbox; in particular, the SVN integration looks like it might actually be usable (unlike a few I've tried - hence I currently use the excellent TortoiseSVN in explorer). The prices don't look too terrible (but it is a little odd that there isn't a bundle for the pair).

Wednesday 8 April 2009

Re-implementing Expression for Compact Framework

Background

In this previous post I gave an indication of how the RPC stack of protobuf-net is implemented - in particular (in .NET 3.5) with Expression - allowing:
  ProtoClient<IMyService> client = ...
double amount = client.Invoke(svc => svc.DoSomeMaths(
12, someObj.Qty));
where DoSomeMaths is a method defined on the IMyService interface. This works well, and avoids the need to do any kind of code generation, yet still have full static (compile time) checking that we're using methods that are defined on our service.

So what is the problem?

As always, there is a fly in the ointment; it transpires that the Expression API doesn't exist on Compact Framework 3.5. Perhaps Microsoft thought that it served little purpose without a matching Reflection.Emit implementation (allowing you to compile expressions to delegates) - who knows. But it is vexing that it works everywhere (including Silverlight 2.0) except here. So what can we do?

Well, pretty-much all of C# 3.0 is actually compiler magic hitting known types in the base class. For example, you can use LINQ (with delegates) with C# 3.0 targetting .NET 2.0 by declaring ExtensionAttribute and adding a pile of extension methods on IEnumerable etc (or more simply: download LINQBridge). So can we do the same here? I've previously always been dismissive of this, but it turns out that yes, we can.

What, all of Expression?

First - a caveat; I don't need all of Expression; for example, I don't need any compilation features, I don't need to be able to add things etc - all I need is:
  • 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)
Anything more complex, and the caller can simply pre-calculate their argument value into a variable, and pass that in via a capture - i.e. this won't work:
  double amount = client.Invoke(svc => svc.DoSomeMaths(
12, someObj.Qty * 2));
but this will:
  int qty = someObj.Qty * 2;
double amount = client.Invoke(svc => svc.DoSomeMaths(
12, qty));
What is involved?

Actually, not a vast amount - but we are hampered a bit; the C# spec doesn't actually indicate what Expression features it uses, nor when. Very unusual for C#, which is usually very detailed in this sort of thing... but actually, we can get an appreciation of what we need from looking at what the compiler does behind the scenes (as discussed previously). Given the requirements above, it turns out that we need the static methods:
  • Expression.Constant
  • Expression.Parameter
  • Expression.Field
  • Expression.Property
  • Expression.MethodCall
  • Expression.Lambda<T>
and a few classes to hold the state for each of these, so that we can inspect it afterwards. Not a huge task at all.

plz send teh codez

OK, enough already... the code for this (and it isn't very much) is now committed into protobuf-net (but only applies to the CF35 build) - and is available here - at just over 250 lines (including comments), this seems a fairly pragmatic way of unifying service access over the different frameworks. Enjoy.