Tuesday, May 31, 2011

CodeDOM and poor man's lambdas -- Part 2

Unfortunately there is one major sticking point in getting the generation to work for F# -- local variables are declared as let mutable rather than as a ref type which means that the necessary closure cannot be made; this is rather stronger than the lack of support for CodeDefaultValueExpression, which can be fudged around, or for nested types (which just become mutually recursive), though with up-front decision as to the language to generate (rather than making the choice following the expression tree), we could replace problematic elements with snippets.

That aside, the main operation looks like this, similar to the previous examples

If we eschewed F# support entirely, and used a partial class, then we could skip the constructor and field declarations and provide the input by any other mechanism of our choice in a hand-written part.

Generating the closure classes is a simple matter -- especially as the names of the parameters can be used as fields directly without any sigils, provided that they never contain the @this or proxy name by convention. This makes the closure class approach slightly simpler than a snippet driven use of direct lambda syntax, where local variable names to hold out parameters would in general have to be generated so as not to clash with any of the arguments:

where the individual field declarations have to work around the decorations for out or ref, thus:

The generation of the proxy methods is equally mechanical

So, given a simple type

we generate

The F# code contains


Manually replacing this with


then shows up on the next line

as an error The mutable variable 'proxy' is used in an invalid way. Mutable variables cannot be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via 'ref' and '!'.; and as there are no readonly locals in the CLR -- it's all F# compiler magic that gives the illusion of same -- we're stuck with no control to tweak to make proxy immutable in the F# output.

No comments :