Tuesday, August 31, 2010

HyperJS Episode 2 - Attack of the Accessors

JavaScript in C# IS NOT ExpandoObject

Posts in the HyperJS Series

Last time, I discussed the first step on the road to JavaScript in C# in my HyperJS Episode 1 - The Phantom Project post. It covers the original intent of my weekend prototyping and the result: HyperDictionary - An implementation of IDictionary<string, object> with "inheritance," overrides, and extensions. All of the projects I'll talk about in this series are available on (my first) GitHub repos: http://github.com/tchype.

In part 2, I'll be covering how Rob Conery's post that I'll incorrectly label "Trying to implement Ruby Hashes In C# But C# Leaves A Lot To Be Desired In That Regard (I know, Oren, Use a Dynamic Language If I want Dynamism)" was an influence once I realized I was headed down this path, how I really just wanted a simple feature, and how I had to build it myself. Then, once I did it (very easily), I started down a weird and fun path of seeing if I could make JavaScript in C#.

HyperJS Part 2: HyperDynamo

Now that I had created a HyperDictionary, I was wondering how hard it would be to allow a Dictionary to be populated by a data source using the key/value pairs defined in the data store, but then accessed via the dot-notation of a property name. The thought here is that although a data-store-driven key/value pair allows you to arbitrarily add a key and value, typically you have to write code to use it anyway. With recordsets and dictionaries, you typically create constants somewhere in your code (because, after all, we all want to keep it DRY, right?) and then have this kind of annoying code all over your project:

public const FIRST_NAME_KEY = "first_name";
public const LAST_NAME_KEY = "last_name";
...

// Read from DB into an object
var user = new Person()
 { 
   FirstName = record[FIRST_NAME_KEY], 
   LastName = record[LAST_NAME_KEY],
   // ... more properties ... 
};
...

//Set the user's first name into a ViewData key
ViewData["user_first_name"] = user.FirstName;

Just to be clear: I don't actually code directly against the recordset in the view or controller...I like ViewModels and DTO objects and exception handling; this is just an obscene example that illustrates the point of using constants to reference field and key names.

After seeing Rob Conery's post on doing Ruby-esque things in C# (and having done some in MVC and side Rails projects), I wondered if it would be possible to do something more like JavaScript...wouldn't it be nice if you had the option to easily populate an object's properties by looping through the key names and setting their values (ignoring the tight coupling and issues with valid property name validation):

dynamic user = new ExpandoObject()
foreach (string key in myDictionary.Keys)
{
  user[key] = myDictionary[key];  //Actually, this is an Exception...
}

Even when we use constants for key names, we are essentially compiling the key names in for those keys we know and care about and write code against. And then, in cases of quick internal apps, prototypes, or just for eliminating the need for the stupid constants, we could just reference the properties we care about against the dynamic binding:

ViewData["user_first_name"] = user.first_name

ExpandoObject Is Not Good Enough

Although ExpandoObject is really cool, it relies purely on dot-notation property setters and getters (no indexers), so this doesn't actually serve the purpose. So I had seen the idea to back a dynamic object with a Dictionary in an MSDN article describing the DynamicObject class in .NET 4. The purpose of that was to demonstrate how you could change the behavior of the property name routing through TryGetMember/TrySetMember (in this case, to all lower-case); I'm sure this is what the IronRuby team used some of to map into ruby-style method and property names...but I digress.

Happy Birthday, HyperDynamo!

I created my own class, inherting from DynamicObject, backed by any implementation of IDictionary<string, object> that overrides the TryGetMember and TrySetMember and maps property names to key names directly and stores the value in the value portion of the KeyValuePair. I suck at naming, so Hyper ("more than", and also my Ayende-esque "Rhino-type" prefix) and Dynamo (for "dynamic") because it's more than the basic DynamicObject class. I also implemented the indexer on a string name and IEnumerable<KeyValuePair<string, object>> so that I could access properties via:

  1. Dot-notation
  2. Indexer (e.g., foo["bar"]) for both setters and getters
  3. And use foreach to iterate through the properties

It's Your Birthday, Go HyperDynamo!

So, with ease, I can now do JavaScript-style assignment, retrieval, and iteration on HyperDynamo objects in C#! Take a look:

dynamic person = new HyperDynamo();
person.FirstName = "Tony";
person.LastName = "Heupel";
person["MiddleInitial"] = "C";

Console.WriteLine("Hello, {0}, {1}., {2}!", person["FirstName"],
                              person.MiddleInitial, person.LastName);

This displays what you would expect:

Hello, Tony C. Heupel!

That's Cute, But Hardly JavaScript

Very true. Again, my original goal was not to create JavaScript in C#, but rather to enable some JavaScript (and other dynamic language) style for reducing complexity of mundane work and impedance mismatch. But, did you notice something? While HyperDynamo uses a Dictionary<string, object> by default, it really only requires any object implementing IDictionary<string, object>--including a HyperDictionary with Prototype-style inheritance!

Next Up -- Part 3: HyperHypo

The sucky names continue, but things get interesting once you start combining what I have placed into my HyperCore assembly together, mix in a pinch of closures, and top it off with a smidge of real JavaScript concepts...check out Hyper JS Episode 3 - Revenge of the Script!

Monday, August 30, 2010

HyperJS Episode 1 - The Phantom Project

JavaScript in C# starts with Prototype Inheritance

Posts in the HyperJS Series

Last weekend, I worked on my first Github projects: HyperCore, HyperJS, and HyperActive (I like "Hyper" as my project prefix since my name is pronounced "High-pull"). You can find them at: http://github.com/tchype.

In part 1, I'll be covering my original free time prototyping that, a week later, has resulted in the start of something I find very interesting and fun, even if it ends up being pointless...JavaScript-style coding in C#. That first step is something I call HyperDictionary

HyperJS Part 1: HyperDictionary

The original goal of my free-time project was to create a Dictionary of key/value pairs that supports inheritance and overriding of values--a sort of HyperDictionary since it exists in multiple dimensions once you include the ancestors. This had come out of some challenges my friends were facing at work with dealing with customer contracts that had sub-contracts that mostly followed the main contract but had some changes per sub-contract. I wasn't working directly on it myself but I had to scratch that itch at home...

I created a HyperDictionary class that implements IDictionary<string, object>. It allows you to specify a "parent" IDictionary<string, object>. It also allows you to Add, Remove, or Extend values based on their keys and types. You can Add or Remove any key from the dictionary and you can Extend any IEnumerable.

I was inspired by two things:

  1. ASP.NET Web.config: The AppSettings section lets you add and remove key/value pairs at the machine level, your web site level, or a particular folder within a web site, always referring back to the higher level to find settings.
  2. JavaScript: Prototype inheritance seemed to be the way to go, where you can see if a dictionary "HasOwnProperty(name)" and if not, asking for a key will then check it's parent to see if it has it, and so on.

Examples

In this first example, we simply define a top-level dictionary--top--and a second level dictionary--second--where one property is only defined in top and the other is overridden in second:

Console.WriteLine("Using HyperDictionary to show dictionary inheritance\n==================================================");
var top = new HyperDictionary("top");
top["eyes"] = "brown";
top["hair"] = "pointy";

var second = new HyperDictionary("second");
second.InheritsFrom(top);
second["hair"] = "straight";

Console.WriteLine("top[\"eyes\"]:\t{0}", top["eyes"]);
Console.WriteLine("top[\"hair\"]:\t{0}", top["hair"]);
Console.WriteLine("second[\"eyes\"]:\t{0}", second["eyes"]);
Console.WriteLine("second[\"hair\"]:\t{0}", second["hair"]);

Which outputs:

Using HyperDictionary to show dictionary inheritance
==================================================
top["eyes"]:    brown
top["hair"]:    pointy
second["eyes"]: brown
second["hair"]: straight

This works n-levels deep as well. Here's an example where I removed a setting and extended an IEnumerable as well:

//Extends and removes using an IEnumerable<object> value
top["things"] = new string[] { "first thing", "second thing" };

var third = new HyperDictionary("third");
third.InheritsFrom(second);
third.RemoveProperty("hair");
third.ExtendProperty("things", new object[] { 3, 4, 5 });

//Output members of third - note the absence of "hair" member
Console.Write("third members:\n");
foreach (object o in third)
{
    Console.WriteLine(o);
}
Console.WriteLine();

// Output the extended list of items in "things", 
// some from top and some from third.
// And notice: DIFFERENT DATA TYPES!
Console.Write("third things:\t");
var things = third["things"] as IEnumerable<object>;
foreach (object thing in things)
{
    Console.Write(" | " + thing.ToString());
}
Console.Write(" | ");
Console.WriteLine();

Which outputs:

third members:
[things, System.Linq.Enumerable+<UnionIterator>d__88`1[System.Object]]
[eyes, brown]

third things:    | first thing | second thing | 3 | 4 | 5 |

Potential Uses

Here's a couple quick ideas for uses of the HyperDictionary:

  • Versioned object serialization: Each version of the object is it's own HyperDictionary that "inherits" from the previous version and it's own KeyValuePairs the deltas. You can store the Tuples as the values (PropertyActions are Add, Remove, Extend) for each version and easily recreate point-in-time versions. You could also store the "current" full dictionary (including ancestor key/value pairs) separately for speed since going back versions is usually a special-case. This works fairly easily with both a no-SQL and a SQL datastore.
  • In-memory data changes: You can read key/value pairs out of a data store (database, cookie, etc.) into a "current settings" dictionary. Then, create a "user changes" dictionary with the "current settings" as the parent. When the user makes changes, it updates the "current settings" dictionary and then you can save the "user settings" dictionary back to the data store, using the proper Add, Remove, or Extend action. Create the "Default Settings" as the top-level dictionary and you can enable "Restore Defaults" very easily.
  • Hierarchical configuration: It was partially based on this concept, should work...
  • Role-based security: You could implement a base set of entitlements that are set to some default key/value pairs (e.g., "CanUseSystem" => true, "CanAuthorizePayments" => false, "CanCreateUsers" => false) and then, based on the user's role or particular account, add or remove or extend their capabilities using a new dictionary at each level.

Next Up: JavaScript Style

In the next post, I'll describe how I wanted to be able to set items using the indexer notation and access that value via a dynamic property reference:

foo["bar"] = "baz";
var gotBar = foo.bar;
From there, it ends up being an easy cognitive jump to JavaScript style (and, you get to use closures in cool ways)! It also ends up to not be an easy jump to implement it "for reals."

HyperDictionary is part of my HyperCore GitHub project that also includes the capabilities I'll describe in the next two posts. http://github.com/tchype