How to create extension methods?

Dynamic currying: part 3

In the last post, it looked like we are done. We created the DOM and it compiled nicely to a library. But calling the methods could be nicer. Right now, it's like this:

FuncExtensions.Curry(someDelegate)

Wouldn't it be great, if we could call it like this:

someDelegate.Curry()

That's exactly what extension methods are for. Just make the class static and add the this keyword. Except both of these are C#-specific. And as I mentioned last time, CodeDOM tries to be language-agnostic, so it doesn't support this.

Isn't there anything we can do? There is a way … But we have to get our hands dirty and use string manipulation. Last time, we were creating the library directly from DOM. But we can convert the DOM to a string containing the C# code, modify that the way we need and then compile the code into a library:

var writer = new StringWriter();

var provider = new CSharpCodeProvider();

provider.GenerateCodeFromCompileUnit(
    compileUnit, writer, new CodeGeneratorOptions { BracingStyle = "C" });

string code = writer.ToString();

code = code.Replace("class FuncExtensions", "static class FuncExtensions");
code = code.Replace("(Func<", "(this Func<");

provider.CompileAssemblyFromSource(
    new CompilerParameters(new[] { "System.Core.dll" }, "Currying.dll") { GenerateInMemory = false },
    code);

The string manipulation code is actually quite simple, but it's fragile. If we wanted to change what we do, we would have to check every time that it's still doing what we want.

Now that we finally have everything we wanted, let's be a little curious: how does the code generated from all those lambdas look like? Horribly.

The lambda for Func with 15 parameters results in 15 different closure classes, nested one inside another. And each of the other lambdas has its own hierarchy. What's worse, every class has references to all its predecessors. This looks quite wasteful, memory-wise, but it saves time that would be otherwise required to get all the parameters.

If I was doing this by hand, I would probably always pass the parameters gathered so far to the next closure class. But this is only possible, because I know the closure is no mutated in any way.

This finishes this series. See you next time.

codedom dotnet c#
Posted by: Petr Onderka
Last revised: 18 Dec, 2014 10:17 PM History

Discussion

25 Jul, 2011 03:49 AM

I found my way here from stackoverflow. I have a dynamic curry implementation too but using the DLR. It proxies based on DynamicObject and dynamic convert itself into being wrapped by a static delegate type to if you cast it. Not as performant as writing a bunch of functions sensibly, but works for all sorts of other things you might want to curry like methods or other dynamic objects that couldn't be done sensibly.

Func<int, int, int, int, int> add = (x, y, z, bbq) => x + y + z +bbq;  //Original function
Func<int, Func<int, Func<int, Func<int, int>>>> curry0 = Impromptu.Curry(add); // curry and then implicit cast
var curry1 = curry0(4);
var curry2 = curry1(5);
var curry3 = curry2(6);
var result = curry3(20); //35!
26 Jul, 2011 08:07 PM

Yeah, I noticed that while I was looking at your source code because of that question.

Your version is certainly interesting too, but I don't like the fact that it's dynamic. Yeah, you can cast the result into the (quite ugly) delegate type, but that's not checked statically. Although dynamic has its uses, I prefer doing things statically most of the time.

Another thing is that the main purpose of this series for me was to learn CodeDOM, which looks like a cool technology (as a much more user-friendly alternative to Reflection.Emit). Currying was just an interesting topic to facilitate that.

Your Comments

Used for your gravatar. Not required. Will not be public.
Posting code? Indent it by four spaces to make it look nice. Learn more about Markdown.

Preview