I reviewed the original MetaClass system code I had working. To mkae it work with the query system I think it'll be better to strip it down and start from scratch. It's possible to start implementing this new stuff now, but I would rather have it built up with this in mind. I can say that the original MetaClass system is useful, but has some annoying issues that I would want to work out.
For example, it's impossible to add per-object attributes at runtime; something that is fine for C++ but for this system it's undesirable. It's also too C++ like in its nature; I have the concept of 'classes' as an integral part of the system, methods are also separate from the normal attributes of the object. For the system to function as desired I'll need to remove this and implement a more flexibile system. The current attribute setup is interesting, I have an 'Attribute' class and an AttributeValue class being derived from it. This idea was to separate the data from the actual attribute - which is fine - but it's a little too restrictive in nature. Instead of inheritance, I'll use composition and store the AttributeValue as a member of the Attribute class. This will allow easy swapping of the values for attributes, even to the point of dropping in an entirely new typed value.
Seeing phantom talk about the concept of a Lua functor reminds me of the original idea behind my metaclass system. The first concept was to provide a 'class' system in C++ that was scripting system agnostic. You would specify your metaclass types, complete with attributes and methods and then operate on them using the API I provided. Admittedly, it didn't provide much of a bonus in 'pure' C++ environments as the extra level of indirection reduced the speed of the system and didn't offer anything else unless you needed 'pure data' classes that could be specified at runtime. However when you couple this idea with the notion of scripted methods it adds a lot more power by opening up the possibility to call scripted methods specified in any bound language. You could even call C++ specified methods or methods via a form of RPC as the marshalling process is somewhat the same - convert native metaclass properties / objects to a form understood by the other system.
So what happened to the prototype system? Quite simply, I started getting bogged down in my own VM implementation as I wanted a custom script system to power it - something that effectively stalled the project. By loosening the original design to incorporate the query interface I've effectively nullified the design of proposed scripting language for the system and been forced to revaluate how it'll be used. This is actually a blessing in disguise as I am now free to work on developing a useful system that reiterates my original goal of it being language agnostic.
So the system in a nutshell:
The 'metaclass' system name will be dropped; instead I will be referring to it as the Entity Object system (at least for now). The overall goal is to allow for complete data-driven game architectures to be formed around it.
This system is all well and good, but now I want some feedback from you guys. Specifically, how would you use this system? What would you use it for? Can you provide examples, if possible?
Usage examples will help when I'm rebuilding the prototype as it'll allow me to begin catering the system to some real-world scenarios instead of building it in isolation.
I could see this system being tremendously useful just as a data warehouse: vector graphics, game data (both runtime and prepackaged), documents, enterprise databases... all kinds of applications could be designed to do interesting things here. But do we really need another storage solution? Do we really need another Relational Database Theory, another XML, another incarnation of S-expressions without all the goofy parentheses?
IMHO, this only becomes really interesting when the system itself provides ways for data to act on itself. RDBMS theory bores me. XML bores me. I've got to have one tool to blob all my data together, and one tool to do interesting things with the data. Lisp is cool because, with code as first-class data, I only need one tool to do both. (Lisp, and first-class-data coding in general, is a land of toys that I've not yet had the chance to explore as deeply as I'd like.)
This may be utterly contrary to your intentions for the system, but if it were mine to mold, I'd have it set up thusly:
- An object, by itself, is a formless void
- The nature, or type, of an object, is determined by how it is "data-tagged"
- Each "data tag" is permitted to record data (including nested objects/tags) as it sees fit
- The behavior of an object is determined by how it is "logic-tagged"
- Each "logic tag" acts as the fundamental aspects of logic that act on data, essentially the functions-half of a typical OOP class hierarchy
A typical thing we might have is a GUI Widget. In OOP GUIs, it is not uncommon to see things like "a PushButton is a subclass of RectangularWidget and ClickableWidget, both of which inherit from Widget." (At least, in C++, where we get multiple inheritance. Translate to the OOP sub-paradigm of your choice.) In this system, a Widget has an abstract Render function; RectangularWidget specifies this by adding Rectangle data and making Render draw the rectangle. ClickableWidgets do analogous things with user input.
In this other system, I'd see it playing out as such: "this particular Object is data-tagged as a Rectangle. The Rectangle tag carries an implicit association of being a type of Shape tag. The Object is also logic-tagged as being Clickable, which carries appropriate semantics for handling user input. Finally, the Object is logic-tagged to handle rendering, and data-tagged to handle specifics such as text label, icon, pushed-state, etc."
So really instead of having a rigid hierarchy of types, we have a pool of data attributes and logical behaviors. There's a method by which we can associate or link things; some Data tags are always implicitly tagged with metadata (all Rectangle tags are metadata-tagged as being Shapes). Some tags always implicitly link to certain behaviors. Logical tags can delegate behaviors to other associated tags if they like.
I don't really have a clear idea of how that would work in a system, how to express it syntactically, or how to derive benefits from this over a strongly-classed paradigm; but it seems like an interesting and promising half-idea [grin]