Monday, February 18, 2013

Groovy generator proof of concept

Many languages such as C#, F#, Python, etc. have syntax supporting the generation of sequences whose elements are computed on-demand (vs. e.g. arrays or lists, which hold all their elements in-memory). Such a feature is conspicuously missing from Groovy.

Let’s take F#, for example. The following is a simple F# sequence expression:
seq {
    yield 1
    yield 2
    yield! [3;4]
    yield 5
}

This expression creates an IEnumerable<int> which yields the elements 1 through 5 on-demand. If we wrap this expression in a Quotation and decompile it with Unquote, we can see its de-sugared form:
seq (Seq.delay (fun () -> Seq.append (Seq.singleton 1) (Seq.delay (fun () -> Seq.append (Seq.singleton 2) (Seq.delay (fun () -> Seq.append [3; 4] (Seq.delay (fun () -> Seq.singleton 5))))))))

Basically, what we get is a series a continuations, similar in concept to what monadic syntax gives in general in Haskell (and indeed, in F# too with the more general concept of computation expressions).

Understanding this, we realize that between standard Java Iterables, Groovy Closures (with a bit of dynamic delegation), and Groovy AST Transformations, we can have a similar generator syntax in Groovy.

First, we’ll implement a type Generator<E> implementing Iterable<E> which generates elements on-demand from a closure composed of nested continuations (no syntactic sugar yet, we’ll get there with AST Transformations later on):


With a static import for Generator.gen, we can create a Generator equivalent to our F# example like so:


First, notice that all of our calls to undefined yield and yieldAll methods are resolved via delegation to Generator yield and yieldAll methods (which return YieldResults, used internally by our Iterable impementation for keeping track of the next continuation). Starting from the root Closure supplied to gen, each call to Iterator.next() returns the first argument supplied to the yield or yieldAll method, saving the second continuation argument for the next next() call, continuing this way until a continuation which returns null ends iteration (with some look-ahead complexities accounted for to accommodate the hasNext() pattern, as well as some complexity flattening out elements supplied to yieldAll).

To demonstrate the on-demand nature of our generator, consider the following tests:


This is all well and good, but no one wants to write all those continuations by hand. We need some syntactic sugar here. This is where AST Transformations come in to play. We will write an AST Transformation which allows us to write our generator expressions like so:


We implement two AST Transformations: YieldTransformation, which de-sugars our generator closure, and GenTransformation, which extends YieldTransformation, constructing a Generator from the de-sugared generator closure:


Note that what we have here is indeed just a proof of concept: the YieldTransformation doesn’t yet handle if / then / else expressions for example (though those cases should be pretty straight forward having implemented the more difficult BlockStatement transformation).

It would be great to see a Generator feature like this brought natively to Groovy in the future (and without the need for AST Transformation, which requires the use of annotations on declaration expressions). The full power of on-demand generators like this become apparent when used in conjunction with on-demand Iterable transformation libraries such as Tim Yates' groovy-stream or my own Functional Java (yet to be ported for friendly use from Groovy).

Monday, August 27, 2012

Move svn history from one repository to a GoogleCode repository

I keep a private Assembla svn repository for little projects that I have going but don’t want to release to the public. However, on two occasions, those little projects have turned into big projects (Unquote and FsEye) which I wanted to move to open source GoogleCode repositories.  Both times I’ve used the following instructions to help me move the svn repositories to with full history intact: http://therightstuff.de/CommentView,guid,b984a8e7-e94d-4eed-a705-5dc479f959e8.aspx.

Friday, July 20, 2012

FsEye 2.0.0 beta 1 release!

I've just released FsEye 2.0.0 beta 1! This release features a plugin system I've been working on and should prove an exciting step forward for FsEye.

You can find the download at https://code.google.com/p/fseye/downloads/listand reference the documentation athttps://code.google.com/p/fseye/wiki/FsEye2Beta.

I'm eager to get feedback and see some great plugins developed!

(cross-post from my Google+ announcement)

Thursday, June 14, 2012

Unquote 2.2.2 released!

Unquote 2.2.2 has been released! From the the release notes:
Make all custom exception types serializable so that they may pass AppDomain boundaries. Other minor fixes and enhancements.
Very happy I made the effort to document the release process recently, and it definitely helped speed things up and keep my confidence!

Tuesday, June 12, 2012

Sunday, May 20, 2012

Unquote 2.2.0 release

Unquote 2.2.0 has been released. This release includes several enhancements around operator decompilation.

Visual Studio Build Output on first build in a newly opened instance

In both VS 2010 SP2 and VS 11 Beta, the first time you build a solution in a newly opened instance of Visual Studio, it will focus on the Output window, but fail to switch the output channel to Output like it usually does (i.e. “Show output from” drop  down list).

This has always bugged me, and has effected me often since usually the last action I would have performed since the last time I used Visual Studio would be the run all my automated tests, so the Output window channel is persisted to Test in newly opened instances.

The solution is simply to toggle the “Show output from” option manually while the build is executing. Sounds too obvious to be worth mention, but the fact is, I never even noticed that drop down list because I am so used to it setting itself automatically in most cases.