The Working Programmer

Going Dynamic with the Gemini Library

Ted Neward

Ted NewardReaders of my articles or blog posts will know this already, but for those who’ve stumbled onto this article (whether by accident or because they thought it was a horoscope), I tend to spend a lot of time looking at other languages and platforms. This is usually done in pursuit of concepts or ideas that help model software more effectively, efficiently or accurately.

One recent trend—though it’s not all that recent—within the Web community has been the pursuit of “dynamic” or “scripting” languages, particularly two of them: Ruby (for which the Ruby on Rails framework, also sometimes called RoR, was written) and JavaScript (for which we have Node.js for executing server-side applications, along with hundreds of frameworks). Both of these languages are characterized by a lack of what we’re used to in the C# and Visual Basic world: strict adherence to what a class defines as the sole definition for what an object consists of.

In JavaScript (a language that’s sometimes characterized by smart-aleck presenters like myself as “Lisp with curly brackets”), for example, an object is a fully mutable entity, meaning you can add properties or methods as needed (or wanted):

var myCar = new Object();
myCar.make = "Ford";
myCar.model = "Mustang";
myCar.year = 1969;
myCar.makeSounds = function () {
  console.log("Vroom! Vroom!")
}

The object myCar, when first constructed, has no properties or methods on it—these are implicitly added when the data values (“Ford,” “Mustang,” 1969 and the function) are set to those names (make, model, year and makeSounds). In essence, each object in JavaScript is just a dictionary of name/value pairs, where the value of the pair can be either a data element or a function to be invoked. Among language designers, the ability to play with type information like this is often called a Metaobject Protocol (MOP), and a constrained subset of this is often called aspect-oriented programming (AOP). It’s a flexible, powerful approach to objects, but one that’s very different from that of C#. Rather than try to create a complex class hierarchy in which you try to capture every possible variation through inheritance, as traditional C# object design would suggest, the MOP approach says that things in the real world aren’t all the exact same (except for their data, of course), and the way in which you model them shouldn’t be, either.

Developers who’ve been part of the Microsoft .NET Framework community for many years now will recall that an earlier version of C# introduced the dynamic keyword/type, which allows you to declare a reference to an object whose members are discovered at run time, but this is a different problem. (The dynamic feature set makes it easier to write reflection-style code, not create MOP kinds of objects.) Fortunately, C# developers have the option of both: traditional static type definitions, through the standard C# class design mechanisms; or flexible type definitions, through an open source library called Gemini that builds on top of dynamic functionality to give you near-JavaScriptian features.

Gemini Basics

Like a lot of the packages I’ve discussed in this column, Gemini is available through NuGet: “Install-Package Gemini” in the Package Manager Console brings the goodness into your project. Unlike other packages you’ve seen, however, when Gemini is installed into the project it doesn’t bring an assembly or two (or three or more). Instead, it brings with it several source files and puts them into a folder called “Oak” and adds them directly to the project. (As of this writing, Gemini 1.2.7 consists of four files: Gemini.cs, GeminiInfo.cs, ObjectExtensions.cs and a text file containing the release notes.) The reason for the folder named Oak is actually very reasonable: Gemini is actually a subset of a larger project (called, not surprisingly, Oak) that brings a lot of this dynamic programming goodness to the ASP.NET MVC world—I’ll explore the larger Oak package in a future column.

Of its own accord, the fact that Gemini is delivered as source really isn’t a big deal—the code lives in its own namespace (Oak) and will simply be compiled into the project as the rest of the source files are. On a practical note, however, having the source files makes it absurdly easy to step through the Gemini source code when something goes wrong, or even thumb through the code just to see what’s available, because IntelliSense is sometimes completely defeated by the use of the dynamic keyword/type.

Getting Started

Again, as is my habit, I begin by creating a unit test project in which to write some exploration tests; into that project I install Gemini and test it out by creating a simple “hello world”-like test:

[TestMethod]
public void CanISetAndGetProperties()
{
  dynamic person = new Gemini(
    new { FirstName = "Ted", LastName = "Neward" });
  Assert.AreEqual(person.FirstName, "Ted");
  Assert.AreEqual(person.LastName, "Neward");
}

What’s happening here is subtle, but powerful: Gemini, the object on the other side of the “person” reference, is a type that’s essentially empty of all properties or methods, until those members are either assigned to (such as in the case of the preceding code) or explicitly added to the object through the methods SetMember and GetMember, like so:

[TestMethod]
public void CanISetAndGetPropertiesDifferentWays()
{
  dynamic person = new Gemini(
    new { FirstName = "Ted", LastName = "Neward" });
  Assert.AreEqual(person.FirstName, "Ted");
  Assert.AreEqual(person.LastName, "Neward");
  person = new Gemini();
  person.SetMember("FirstName", "Ted");
  person.SetMember("LastName", "Neward");
  Assert.AreEqual(person.GetMember("FirstName"), "Ted");
  Assert.AreEqual(person.GetMember("LastName"), "Neward");
}

While I do this for data members here, it’s also equally easy to do this for behavioral members (that is, methods) by setting them to instances of DynamicMethod (which returns void) or Dynamic­Function (which expects to return a value), each of which takes no parameters. Or you can set them to their “WithParam” partners, if the method or function can take a parameter, like so:

[TestMethod]
public void MakeNoise()
{
  dynamic person =
    new Gemini(new { FirstName = "Ted", LastName = "Neward" });
  person.MakeNoise =
    new DynamicFunction(() => "Uh, is this thing on?");
  person.Greet =
    new DynamicFunctionWithParam(name => "Howdy, " + name);
    Assert.IsTrue(person.MakeNoise().Contains("this thing"));
}

One interesting little tidbit arises out of the Gemini library, by the way: Gemini objects (absent any kind of alternative implementation) use “structural typing” to determine whether they’re equal or if they satisfy a particular implementation. Contrary to OOP-type systems, which use the inheritance/IS-A test to determine whether a given object can satisfy the restrictions placed on an object parameter’s type, structurally typed systems instead just ask whether the object passed in has all the requirements (members, in this case) needed to make the code run correctly. Structural typing, as it’s known among the functional languages, also goes by the term “duck typing” in dynamic languages (but that doesn’t sound as cool).

Consider, for a moment, a method that takes an object and prints out a friendly message about that object, as shown in Figure 1.

Figure 1 A Method That Takes an Object and Prints Out a Message

string SayHello(dynamic thing)
{
  return String.Format("Hello, {0}, you are {1} years old!",
    thing.FirstName, thing.Age);
}
[TestMethod]
public void DemonstrateStructuralTyping()
{
  dynamic person = new Gemini(
    new { FirstName = "Ted", LastName = 
      "Neward", Age = 42 });
    string message = SayHello(person);
    Assert.AreEqual("Hello, Ted, you are 42 years old!", 
      message);
    dynamic pet = new Gemini(
      new { FirstName = "Scooter", Age = 3, Hunter = true });
  string otherMessage = SayHello(pet);
  Assert.AreEqual("Hello, Scooter, you are 3 years old!", 
      otherMessage);
}

Normally, in a traditional object-oriented hierarchy, Person and Pet would likely come from very different branches of the inheritance tree—people and pets don’t generally share a lot of common attributes in a software system (despite what cats think). In a structurally or duck-typed system, however, less work needs to go in to making the inheritance chain deep and all-encompassing—if there’s a human that also hunts, then, hey, that human has a “Hunter” member on it, and any routine that wants to check on the Hunter status of the object passed in can use that member, whether it’s a human, cat or Predator drone.

Interrogation

The trade-off in the duck-typing approach, as many will note, is that the compiler can’t enforce that only certain kinds of objects can be passed in, and the same is true of Gemini types—particularly because most Gemini code idiomatically stores the object behind a dynamic reference. You need to take a little extra time and effort to ensure the object being handed in satisfies the requirements, or else face some runtime exceptions. This means interrogating the object to see if it has the necessary member, which is done in Gemini using the RespondsTo method; there are also some methods to return the various members that Gemini recognizes as being a part of a given object.

Consider, for example, a method that expects an object that knows how to hunt:

int Hunt(dynamic thing)
{
  return thing.Hunt();
}

When Scooter is passed in, things work fine, as shown in Figure 2.

Figure 2 Dynamic Programming When It Works

[TestMethod]
public void AHuntingWeWillGo()
{
  dynamic pet = new Gemini(
    new
    {
      FirstName = "Scooter",
      Age = 3,
      Hunter = true,
      Hunt = new DynamicFunction(() => new Random().Next(4))
    });
  int hunted = Hunt(pet);
  Assert.IsTrue(hunted >= 0 && hunted < 4);
  // ...
}

But when something that doesn’t know how to hunt is passed in, exceptions will result, as shown in Figure 3.

Figure 3 Dynamic Programming When It Fails

[TestMethod]
public void AHuntingWeWillGo()
{
  // ...
  dynamic person = new Gemini(
    new
    {
      FirstName = "Ted",
      LastName = "Neward",
      Age = 42
    });
  hunted = Hunt(person);
  Assert.IsTrue(hunted >= 0 && hunted < 4);
}

To prevent this, the Hunt method should test to see if the member in question exists by using the RespondsTo method. This is a simple wrapper around the TryGetMember method and is intended for simple Boolean yes/no responses:

int Hunt(dynamic thing)
{
  if (thing.RespondsTo("Hunt"))
    return thing.Hunt();
  else
    // If you don't know how to hunt, you probably can't catch anything.
  return 0;
}

By the way, if this all seems like fairly simple boilerplate or a wrapper around a Dictionary<string,object>, that’s not an incorrect assessment—underlying the Gemini class is that exact Dictionary interface. But the wrapper types help ease some of the type system gyrations that would otherwise be necessary, as does the use of the dynamic keyword.

But what happens when several objects share similar kinds of behavior? For example, four cats all know how to hunt, and it would be somewhat inefficient to write a new anonymous method definition for all four, particularly as all four share feline hunting instincts. In traditional OOP this wouldn’t be a problem, because they’d all be members of the Cat class and thus share the same implementation. In MOP systems, such as JavaScript, there’s typically a mechanism to allow an object to defer or “chain” a property or request call to another object, called a “prototype.” In Gemini you use an interesting combination of static typing and MOP called “extensions.”

Prototype

First, you need a base type that identifies cats:

public class Cat : Gemini
{
  public Cat() : base() { }
  public Cat(string name) : base(new { FirstName = name }) { }
}

Note that the Cat class inherits from Gemini, which is what will enable the Cat class to have all the dynamic flexibility that’s been discussed so far—in fact, the second Cat constructor uses the same Gemini constructor that’s been used to create all the dynamic instances thus far. This means that all of the preceding prose still holds for any Cat instance.

But Gemini also allows us to make declarations of how Cats can be “extended,” so that every Cat gains the same functionality without having to explicitly add it to each instance.

Extending a Class

For a practical use of this functionality, presume that this is a Web application that’s being developed. Frequently, you need to HTML-­escape the name values being stored and returned, in order to avoid accidentally allowing HTML injection (or worse, SQL injection):

string Htmlize(string incoming)
{
  string temp = incoming;
  temp = temp.Replace("&", "&amp;");
  temp = temp.Replace("<", "&lt;");
  temp = temp.Replace(">", "&gt;");
  return temp;
}

This is a pain to remember on every model object defined in the system; fortunately, MOP allows you to systematically “reach in” and define new behavioral members on the model objects, as shown in Figure 4.

Figure 4 Writing Methods Without Writing Methods

[TestMethod]
public void HtmlizeKittyNames()
{
  Gemini.Extend<Cat>(cat =>
  {
    cat.MakeNoise = new DynamicFunction(() => "Meow");
    cat.Hunt = new DynamicFunction(() => new Random().Next(4));
    var members =
      (cat.HashOfProperties() as IDictionary<string, object>).ToList();
    members.ForEach(keyValuePair =>
    {
      cat.SetMember(keyValuePair.Key + "Html",
        new DynamicFunction( () =>
          Htmlize(cat.GetMember(keyValuePair.Key))));
    });
  });
  dynamic scooter = new Cat("Sco<tag>oter");
  Assert.AreEqual("Sco<tag>oter", scooter.FirstName);
  Assert.AreEqual("Sco&lt;tag&gt;oter", scooter.FirstNameHtml());
}

Essentially, the Extend call is adding new methods to every Cat type, suffixed with “Html,” so the property FirstName can be accessed in an HTML-safe version by calling the FirstNameHtml method instead.

And this can be done entirely at run time for any Gemini-­inheriting type in the system.

Persistence and More

Gemini isn’t intended to replace the entirety of the C# environment with a bunch of dynamically resolved objects—far from it. In its home usage, inside of the Oak MVC framework, Gemini is used to add persistence and other useful behavior to model classes (among other things) and to add validation without cluttering the user’s code or requiring partial classes. Even outside of Oak, however, Gemini represents some powerful design mechanics, which some readers may remember from part 8 of my Multiparadigmatic .NET series from a while back ( msdn.microsoft.com/magazine/hh205754).

Speaking of Oak, that’s on tap for next time, so stick around to see how all this dynamic stuff plays out in a real-world scenario.

Happy coding!


Ted Neward is a principal with Neward & Associates LLC. He has written more than 100 articles and authored and coauthored a dozen books, including “Professional F# 2.0” (Wrox, 2010). He is an F# MVP and noted Java expert, and speaks at both Java and .NET conferences around the world. He consults and mentors regularly—reach him at ted@tedneward.com or Ted.Neward@neudesic.com if you’re interested in having him come work with your team. He blogs at blogs.tedneward.com and can be followed on Twitter at twitter.com/tedneward.

Thanks to the following technical expert for reviewing this article: Amir Rajan (Improving Enterprises)
Amir Rajan is a principal consultant with Improving Enterprises. He's an active member of the development community and has expertise in ASP.NET MVC, HTML5, REST architectures, Ruby, JavaScript/CoffeeScript, NodeJS, iOS/ObjectiveC and F#. Rajan is a true polyglot with an unwavering passion for software. He's on Twitter at @amirrajan and on the Web at github.com/amirrajan, amirrajan.net and improvingenterprises.com.

 

Rate: