First-class relationships in an object-oriented language
This paper outlines a kind of programming that bridges the object-oriented and relational worlds in quite a nice way.
When programming Model-View-Controller patterns, I tend to think that there is an equivalence between model and database. The model is the repository of all of the information relating to the state of the application, while the relational database is the repository of all the information relating to the state of the enterprise. Obviously, the scope is different, but many of the data design problems are similar. Just as with an enterprise relational database, you want to design for the data, in the hopes that a well structured schema will persist over time, as the demands on it change from iteration to iteration. Object-oriented databases are one way of approaching this problem, and with the advent of Linq in the C# world, the day of being able to arbitrarily query the model may soon be upon us.
One of the problems with the object database approach is that of defining and maintaining relationships between objects/entities. As object-oriented programmers, we tend to want to be able to say foo.bar and have that mean “the bar objects that belong to foo“. But what happens when we want access the reverse relationship, bar.foo. Assuming that the relationship of foos to bars is many-to-many, both foo.bar and bar.foo should represent multiple objects, or collections. The problem is keeping the maps of foos-to-bars and of bars-to-foos in sync.
The paper above outlines an interesting approach in which the relationships between classes are separate from the classes themselves. Now, a traditional object-oriented language can do this, but the syntax is awkward, and the authors propose a java language variant (with its own compiler), that supports first-class relations.
Interestingly enough, as part of the Linq system, C# will acquire a mechanism by which first-class relations can be created and defined, with a nice syntax, and without having to write your own language. That mechanism is extension methods, and it has been mooted that extension properties may also be added to Linq, which will enhance the approach no end. (truth be told, extension properties seemed somewhat useless to me until I read the paper above).
A fairly good introduction to extension methods can be found here. Basically, an extension method is a static method, with an explicit “this” parameter, and which is accessible as a method on the the type pf “this“. Probably best if I give an example.
public static class StringExtender
{
public static string CamelCase(this string s)
{
// do my camel case thing
return camel;
}
}
When imported, this class now “adds” the CamelCase method to all string objects. Well, not really, its just syntactic sugar, and in fact its called just like any other static method. Heres how the translation goes:
string s = "how are you gentlemen?"
Console.WriteLine(s.CamelCase())
translated:
string s = "how are you gentlemen?"
Console.WriteLine(StringExtender.CamelCase(s))
So how does this relate to object oriented databases and first class relationships?
Well, consider the following code:
class Trader { /* add stuff to do with traders */ }
class Instrument { /* add stuff to do with instruments */ }
static class TraderInstruments : Relationship<ManyToMany, Trader, Instrument>
{
public static ICollection<Instrument> Instruments(this Trader trader) { return GetFirst(trader); }
public static ICollection<Trader>Traders(this Instrument instrument) { return GetSecond(instrument); }
}
Now what this code is doing is adding a Trader.Instruments() method and a Instruments.Traders() method to the entities I previously defined, without having to modify the Trader or Instrument classes themselves.
I can now do the following:
Trader trader = new Trader();
Instrument instrument = new Instrument();
trader.Instruments().Add(instrument);
Debug.Assert(instrument.Traders().Contains(trader) == true);
Which, by adding a “method” and providing intellisense, is a more readable, learnable and discoverable, and less verbose than the static method calls this might get translated into:
Trader trader = new Trader();
Instrument instrument = new Instrument();
TraderInstruments.Add(trader, instrument);
Debug.Assert(TraderInstruments.Traders(instrument).Contains(trader) == true);
Now the extension method approach works very well for many-to-many relationships, but its gets a bit ugly for one-to-many and many-to-one relationships, in that what should really be nullable extension properties is instead represented by extension methods returning collections constrained to contain 0 or 1 item only.
Even so, the possibility of separating the relationships from the entities seems like quite a powerful mechanism. You can easily add or change relationships without having to change the entities themselves, while keeping an object-oriented style.
Extension methods are very powerful things, and should be used sparingly (as with implicit type casts and operator overloading), because of the potential confusion they can create about what code is being executed. Even so, I think they are a great addition to the language.
Basta!


April 12th, 2006 at 2:50 pm
(Caveat: off the top of my head .. no compiler on this particular machine)
public static class UniversalBagExtension
{
private static Dictionary bag = new Dictionary();
public static IList GetItems(this TContainer container)
{
if (!bag.HasKey(container))
{
bag.Add(container, new Dictionary();
}
if (!bag[container].HasKey(typeof(TItem)))
{
bag[container].Add(typeof(TItem), new List());
}
return bag[container][typeof(TItem)];
}
}