Id call it something like 'context' with a fancy word added to it somewhere.
What it attempts to solve:
Many classes need some context to function properly. Access to file managers, heap allocation, physics simulators, objects managing this and that, all kinds of managers. In order for the instances of these classes to operate with their data, they need access to these 'managers' which manage the actual data - their members are usually just indices/references to the data managed by these managers, and thus useless if the correct manager is not available.
So, for these classes to function, they need:
-Managers
-Indices to data managed by the managers
So, how do we ensure the object has access to the managers it needs?
a) The object has a reference to the required managers
*Code that uses the objects needs no knowledge of the resource pools/managers it needs
b) The managers are passed to the object from the user of the class
*In many cases, the using code is aware of at least most of the managers - storing them in the class would be a waste of memory
There is no problem with (a), thats simple. (b) would be used for example in a class that manages all your game objects. All of them probably use the same physics, graphics, files... so each storing their own references to the managers they need would be evil. So, when the game object manager does operations on your game objects, the required managers would be passed there by the game object manager.
class GameObjectManager
{
void doOperation()
{
for object in objects
{
object.operation(mgr1,mgr2);
}
}
vector<GameObject> objects;
ThisManager& mgr1;
ThatManager& mgr2;
}
class GameObject
{
void operation(ThisManager& mgr1, ThatManager& mgr2) //managers passed in instead of stored
{
mgr1.getObject(r1).doSomething(mgr2.getObject(r2));
}
ThisComponentRef r1;
ThatComponentRef r2;
}
This is ok. But its not pretty. What happens when you need not only 2 (which already is too much) but 10 managers for the GameObject to access all its members? For a single method, not a problem, but if you have 10 methods, that means youd be passing 10 arguments to each of them, even if you were calling them one after another? Would it not feel redundant?
What we want to do, is to create a context object, that stores all the variables that the accessor knows about and that the object needs to work.
void doOperation()
{
for object in objects
{
object::context c(PhysicsMgr,FileMgr,SoundMgr,Allocator...) //optionally the class containing doOperation() could get these variables from its own context - someone is calling doOperation, and is likely aware of at least some of the above managers, so why store them in the class of doOperation()?
object.operation(c,1,true,"hue"); //is this similiar to multiple dispatch? we need both object and the context to do the operation...?
object.doAnotherOperation(c,...);
object...
}
}
Now, that is already a lot of saved writing. As mentioned, you might want to 'chain' the contexts, as in doOperation() would itself receive a context, and that context would be used to fill in the context of object - something like a heap allocator would probably be used like this.
So, a method of a class that needs managers (to make its resource indices accessible), needs:
-The class (for the indices to managers and data stored directly in the class instance)
-The context (supplied by the caller of the methods of the object)
-The managers
You could say you call the method like (GameObject,Context).operation() but of course thats not possible. Maybe with some template magic.
A class would be composed of:
-Its methods
-Its directly stored variables (primitive types for example)
-Its indirectly stored variables, an index to a manager (RAM is just a global manager?)
The context is not store in the class, it is created in the scope where the classes methods are accessed, although the context should be described within the class (what types of variables are needed as context)
If we take this further, outside what is already possible within the constraints of the language, this could be even more streamlined.
For example:
-Instead of creating a separate 'context' class, the context variables would become a part of the class. This gets rid of all unneeded parameters of methods.
class Object
{
public:
void operation(){};
private:
PhysicsComponentIndex index;
...
context: //does not add to sizeof(class), stored in scope of access and must be set each time before access
PhysicsMgr& mgr;
void setPhysicsMgr(PhysicsMgr% mgr){[context/this?]->mgr=mgr};
implicit HeapAllocator& alloc; //yay a keyword, let me explain
}
-An implicit keyword (as in the above piece of code). This means the object is automatically grabbed from the context of the object whose method is using the object. If GameObjectContainers method uses GameObject, the HeapAllocator of GameObjectContainer will be automatically stored in the context of GameObject. This is to reduce typing, which is the whole point of this whole post.
-Ability to combine the context of an object and the object itself, so that code unaware of the required context can process the objects.
Lets use a too long keyword for this, "indepenent"! YAY!
Object& A=getASomehow(); //context object created to scope of this method, implicit context variables filled if possible
A.setHeapAllocator(alloc); //lets say we know this wont work implicitly for whatever reason
A.setPhysicsMgr(physics);
independent Object B=A; //takes the context,stored in the scope of this method, and puts them in an object that contains the context in itself (instead of the context being only in the scope of the method)
RandomFunctionLivingInUnawareness(B); //the function must specify to take indepenent object for this to work. If context is not used by the object, everything will work like before.
-The context of an object is of course affected by inheritance. If i want an object that can use my heap allocator, i can inherit from it. This kind of 'pure' context inheritance where all you inherit is the context description might be better to be seen as separate from normal inheritance, as it doesnt add anything to the class, just states its requirements.
-Method/function specific contexts. I already described each class having a context, but it would be nice to have a 'free' context object, which basically states that "for each object accessed after me in the body of this method, use my variables to fill in all the implicit context variables of those objects". example:
class baaar
{
foooo()
{
std::context<HeapAllocator&> c(alloc); //each object after this will fill their implicit context variables with alloc, instead of using the allocator of baaar.
MyObject meh(); //implicitly uses alloc, assuming MyObjects context needs a HeapAllocator
meh.doStuff(); //can use alloc to allocate stuff
c.magicallyInvalidate(); //now baaars context will be used
meh.doOtherStuff(); //still uses alloc - the context was created already
MyObject dur(); //uses otherAlloc
}
context:
HeapAllocator& otherAlloc;
}
The benefits of something like this will grow as more methods are called and more 'managers' and implicit stuff like heap allocators are used.
Im sure there are other uses than what ive described for a feature like this, as well as obviously making for a more streamlined way of writing code, with all those loggers and allocators and whatnot not in the way anymore.
Discuss.