In brief: I wanted to replace
if (a != null && a.b != null && a.b.c != null) {
return a.b.c.d;
}
else {
return null;
}
by
return andand(a.b.c.d);
and I manged to learn a little bit about monads, generalized algebraic data types, and .NET on the way to achieving
return andand(() => a.b.c.d)
About a month ago I was working with an instance of a generic type:
var page = Potpourri.Page.getPage(s, count.Value);
ViewData["reverse-memento"] = page.reverseMemento.itemNumber;
This code obtains a range of rows from a database given a starting position and a window size. Simple integer offsets don't work for the general case of concurrent access by lay users to a mutable table. My approach requires getPage to know an equivalence relation on elements, but it doesn't require that getPage know about itemNumber specifically or even that there be just one field/property that's sufficient to determine equality.
So, AFAICT, there's no good way to avoid violating Demeter here.
Certainly there remains a practical problem that the next and previous page references could be undefined for any given page. In this case, reverseMemento could be null.
The awkward conditional needed to avoid NullReferenceException here brought to mind Object#andand. Informally, andand provides short-circuit behavior for chained accesses. The Ruby andand relies on Ruby metaprogramming features. The closest thing we have to a macro facility in c# is Linq expression trees, and I hadn't had an excuse to use System.Linq.Expressions yet, so this seemed like a good opportunity.
My first implementation directly transformed expression trees, replacing member accesses by conditional member accesses that return null whenever a is null in a.b.
My second implementation was inspired by a question about the relation between andand and the Maybe monad. I thought it would be a good idea to (re)read some papers about monads and test my understanding by implementing a few, including Maybe Monad. I also thought it would be instructive to implement Maybe monad in terms of andand, and andand in terms of Maybe monad.
I'll discuss the code in detail in my next post. For now, you can download a snapshot. I guess I'll migrate my existing hg repo to googlecode in time for the next post to make browsing easier.