MMXX Overview

MMXX (pronounced "2020" as per roman numerals, or "mix", depending on personal preference) stands for Modules and Metaclasses ++. Accordingly, MMXX is two things:

Using MMXX: a Snapshot

While MMXX is fairly easy to learn to use and understand, it's most often the case that legacy code can't be ported to it without major revision. This is because MMXX only allows a subset of C++ to be used in MMXX-enabled classes. Here are some of the limitations:
Note that not all classes in an MMXX application are MMXX classes - regular C++ classes are also allowed and can derive from MMXX classes, without restrictions. MMXX classes can also have private non-MMXX bases. In essence, only the portion of the design that will be exposed across module boundaries and/or queried through the metaclass interface needs to be MMXX-enabled.

In addition, MMXX requires the full integration of certain constructs into the application's design:

Metaclass Interface Overview

The facilities in MMXX's metaclass interface are optional; your application can rely on MMXX to address the fragile base class problem without using them. However, frameworks, gateway-type software and other advanced applications will potentially find them very useful.

MMXX maintains these runtime objects to match their compile-time equivalents:

MMXXUnit, MMXXClass and MMXXSymbol are themselves implemented as MMXX-enabled classes so that MMXX can itself be revised without suffering from the fragile base class problem (indeed, there are MMXXClass instances for these classes also!)

While the above are high-level representations, MMXX also uses some low-level types to refer to units, classes and objects:

While MMXXMetaunit and MMXXMetaclass offer little additional functionality (indeed, an application does not often use them explicitly, and when it does it will usually ask MMXX to retrieve the pointers to their matching MMXXUnit and MMXXClass instances,) MMXXMetaobject is very significant in that it can be used to uniquely identify any instance of a MMXX-enabled class.

Like an object pointer (and like an x_ptr<>), a MMXXMetaobject variable identifies a class along with an instance (so that two different values for the variable can indeed refer to the same object.) Unlike a pointer, an MMXXMetaobject is not bound to a particular base class. Yet it's possible to convert from a MMXXMetaobject variable to an x_ptr<C> and vice versa, as long as C is a base class for the object in question, as follows:

x_ptr<C> p, q;
p = new C; // as usual, implicitly convert from C* to x_ptr<C>
MMXXMetaobject mp = p._GetMO(); // mp now refers to *p
MMXX_ProtoDynCast(q, mp); // now q == p

Now assume that D is not one of C's base classes, then:

x_ptr<D> r;
MMXX_ProtoDynCast(r, mp); // does not succeed, r is set to null (and MMXX_ProtoDynCast returns false)

In other words, MMXXMetaobject is somewhat like a void * in that it can refer to any object. Unlike a void *, no type information is actually lost.

Functor interface

Like an MMXXMetaobject refers to a generic object, a functor is an MMXX type that refers to a generic class method of a given signature. Functors are very similar to method pointers, except that: Here's another comparison between functors, method pointers and function pointers: Functors are implemented with class templates. Here's an example of their use, assuming there exists a class named foo with a non-static method named bar with signature int bar(double) :

xf_method_1R<int,double> myFunctor; // declare a method functor with signature int (double)

MMXXClass *fooClass = ...; // obtain pointer to foo's MMXXClass instance
fooClass->FindSymbol("bar", &myFunctor); // find method named "bar" and bind myFunctor to it

x_ptr<foo> fooObject = new foo; // instantiate foo
MMXXMetaobject fooMetaobject = fooObject._GetMO(); // obtain MMXXMetaobject for *fooObject

int result = myFunctor(fooMetaobject, 123.456); // same as result = fooObject->bar(123.456)

Note that myFunctor could be rebound to a different method (with the same signature) of a completely different class. Also note that if fooMetaobject did not in fact refer to an instance of foo or one of its subclasses, a bad_cast exception would be thrown when myFunctor is invoked.

Here's a quick summary of functor types:

xf_constructor_0
xf_constructor_[1..10]<partypes...>
Constructor functors, where 1..10 is the number of parameters in the signature as listed in partypes...
xf_destructor Destructor functors.
xf_method_0[C][N]
xf_method_[0-10][R][C][N]<[restype][partypes...]>
Non-static member methods, where C optionally denotes a const method, N a method with an empty throw declaration, R a method that returns a non-void result as specified in restype, and 0..10 is the number of parameters whose types are listed in partypes...
xf_static_0[N]
xf_static_[0-10][R][N]<[restype][partypes...]>
Static member method, where N optionally denotes a static method with an empty throw declaration, R a static method that returns a non-void result as specified in restype, and 0..10 is the number of parameters whose types are listed in partypes...

Metastubs interface

The metastubs interface provides an extra layer of abstraction on methods that can be used by advanced metacode gateways. Metastub pointers are similar to functors, except that they're also fully generic on signatures and can be invoked by signature-independent code.

Synthetic classes

A (backward-compatible) future release of MMXX will provide support for synthetic classes, or classes defined at runtime from an arbitrary set of base classes and (possibly overriding) methods.

MMXX, CORBA and COM

MMXX, CORBA and COM have some overlap in functionality, but have radically different feature sets and areas of applicability. The greatest common denominator is that all three systems can be used to address the fragile base class problem, and that all three offer interface repositories. Yet it is largely an undue generalization to consider them as substitutes. For an overview of how these systems differ, please see the MMXX Frequently Asked Questions.