One unique feature of COM object aggregation is the ability to (usually) load additional functionality on top of an existing class that was silently only known about by you. This is similar to Objective-C category loading, and TOM object extensions -- where methods are loaded onto an existing class.
This is a useful and powerful mechanism for creating "domain specific" convinence extensions to existing classes, without creating a dependency on the class hierarchy.
One simple example is creating a sprintf() style format operator for strings. Even if the String class were not declared final, it would be inconvinent to subclass the this class, because all pre-initialized data "strings" would not be of your new subclass. Therefore, it's much more useful to be able to declare a functionality "extension", which in the context of your assembly is always available on any string type. The behavior would be something like:
// the new extension/enhances keywords..
extension sprintf_format enhances string {
public String fmt(params object[] elements) {
// ...
}
}
Using this would be as simple as calling the fmt method on a
string.
print("This string has an %s".fmt("extension"));
However, an extension would implicitly apply to any object which was
derived from the extended class as well.
// imagine string is not final
class mystring extends string {
mystring(String foo) {
super(foo);
}
char last_char() {
return foo[foo.length-1];
}
}
// the extension still works...
mystring a = new mystring("Testing %s").fmt("fmt");
In the case above, the extension has no state (like a Category in
Objective-C), and thus implementation is trivial. The "fmt" method can
just be converted into a static method which takes the original type
as it's explicit first paramater. i.e.:
class sprintf_format_extension {
static public String fmt(String base, params object[] elements) {
}
}
In the case where the extension wants to store state, the state could
be stored in a keyed array using the object hash code. Looking up the
extension instance would happen as the first part of the method:
class sprintf_format_extension {
static Hashtable extension_instances;
int mode; // my state...
static public void
lookupExtensionState(ref sprintf_format_extension instance, Object a) {
if (instance != null) {
return;
}
if (extension_instances == null) {
extension_instances = new Hashtable();
} else {
instance = extension_instances[Object.GetHashCode(a)];
}
if (instance == null) {
instance = new sprintf_format_extension();
extension_instances[Object.GetHashCode(a)] = instance;
}
}
static public String fmt(sprintf_format_extension this,
String base, params object[] elements) {
lookupExtensionState(ref this, Object a);
if (this.mode == 1)
// ...
}
}