Basic concepts

 

Introduction to Introspective framework

Everything is an object

In C++ there is a strong difference between class and object: the first defines exactly the general behaviour in terms of attributes and methods of the second. Within the Introspective framework both of them are C++ objects, instaces of two main C++ classes introspective::Class and introspective::Object.

So, to use an Introspection class we have to create a corresponding object:

#include <introspective/introspective.h>

introspective::Class MyClass("Class name");
introspective::Object object1("First Object",MyClass);
introspective::Object object2("Second Object",MyClass);

In the previous code, the first row defines the class MyClass, the second defines two object belonging to MyClass.

Everything is defined at run-time

In C++ class behaviour is static, in other words we can't add or remove a method or an attribute, in Introspective both classes and objects can do that.

#include <introspective/introspective.h>

introspective::Class MyClass("Class name");
introspective::Object object1("First Object",MyClass);
introspective::Object object2("Second Object",MyClass);
MyClass.define("Pi",PUBLIC,3.14);
object2.define("e",2.7);

in the example above we have defined a new class attribute named "Pi" on MyClass: this means that both its objects ("First Object" and "Second Object") will inherit immediately the new attribute. In the last line we have also defined a new attribute named "e" on the "Second Object" only. We'll show later how to do the same with methods, for now the important thing is that:

  1. classes can modify during runtime the behaviour of their instances;
  2. even objects can modify their own behaviour;

These leads us to the first design principle of Introspective

Introspective is a true object based framework

In the OO paradigm, many of the languages categorized as 'Object oriented' are actually 'Class oriented', since they leverage on a static behaviour defined at class level to which objects must obey. The focus on Introspective instead is always the object, classes - under this point of view - are just particular kind of objects able to define a hierarchy of inheritable behaviour to their instances. Changing the behaviour on an object will modify the object only, changing the behaviour of a class will change the behaviour of the whole hierarchy dynamically.

Introspective hierarchy is dynamic

This is the second design principle of Introspective. Let's go on with our example defining a new class with a different behaviour:

#include <introspective/introspective.h>

introspective::Class MyClass("Class name");
introspective::Object object1("First Object",MyClass);
introspective::Object object2("Second Object",MyClass);
MyClass.define("Pi",PUBLIC,3.14);
object2.define("e",2.7);

introspective::Class AnotherClass("More precise class");
AnotherClass.define("Pi",PUBLIC,3.14159);
AnotherClass.define("e",PUBLIC,2.71828);
AnotherClass.adopt(object2);

The second class defines the same properties as the first one, with a little more of precision. The important part is the last line, in which the "More precise class" is adopting the object of MyClass modifying its inherited hierarchy . From this moment the object2 attributes will be:

  • "Pi" inherited from AnotherClass with a value of 3.14159
  • "e" will be the object's defined one i.e. 2.7

This happens because of the object (and class as well) hierarchy is dynamic.

Message based paradigm

The classic method call  in languages like C++ or Java is to invoke an object bounded function with parameters and a return value. The definition of methods with same name but different parameters modifies the signature of the method and thereby the code actually executed. This is why, in the OO glossary, the method name (or verb) and its parameters are also referred to as 'Messages': they identify univocally the information passed to an object and to which the object is expected to react. Under Introspective, method triggering is performed through concrete messages sent to an object or class (the receiver) and dispatched internally by the object / class itself. If the message is recognized by the receiver, the corresponding code is executed, if not the whole message is passed to its eventual parent class. This mechanism - usefull for implementing the previous two design principles - has also a different formalism vaguely reminiscent of the objective C one:

RESULT = RECEIVER '[' MESSAGE '<<' VERB ']';

So, in order to retrieve an object property in the objects of the example:

#include <introspective/introspective.h>

using namespace introspective;

Class MyClass("Class name");
Object object1("First Object",MyClass);
Object object2("Second Object",MyClass);
MyClass.define("Pi",PUBLIC,3.14);
object2.define("e",2.7);

Class AnotherClass("More precise class");
AnotherClass.define("Pi",PUBLIC,3.14159);
AnotherClass.define("e",PUBLIC,2.71828);
AnotherClass.adopt(object2);

double e = object2 [ msg::GetAs<double>("e") ];

where

msg::GetAs<double> is a message for retrieving a property value as a double

Introspection

Introspective capability for objects and classes to examine their own structure and behaviour is managed through the implementation of the approriate handlers for the following messages:

  • HasMethodCall / HasMethod - returns true if the receiver has a corresponding handler for the method call id;
  • HasProperty - returns true if the  receiver has a property corresponding to the name passed;
  • Inspect - returns a complete list of properties and methods for which the receiver is able to manage / respond;

There is also an overloaded stream output operator for both classes and object that when invoked will send the Inspect message and print on the ostream the msg::Inspect::Result. Back to the example if we want to print on the screen the inspect result for MyClass :

#include <introspective/introspective.h>

using namespace introspective;

Class MyClass("Class name");
cout << MyClass << endl;
Object object1("First Object",MyClass);
Object object2("Second Object",MyClass);
MyClass.define("Pi",PUBLIC,3.14);
object2.define("e",2.7);

Class AnotherClass("More precise class");
AnotherClass.define("Pi",PUBLIC,3.14159);
AnotherClass.define("e",PUBLIC,2.71828);
AnotherClass.adopt(object2);

In this case the output expected will be

@type  : 'Class name'

+ introspective::Class[introspective::msg::Clone] -> introspective::Message::Receiver*
+ introspective::Class[introspective::msg::GetProperty] -> introspective::Property
+ introspective::Class[introspective::msg::Get] -> tsl::Variant const*
+ introspective::Class[introspective::msg::HasMethodCall] -> bool
+ introspective::Class[introspective::msg::HasProperty] -> bool
+ introspective::Class[introspective::msg::Inspect] -> introspective::msg::Inspect::Result
+ introspective::Class[introspective::msg::Is] -> bool
+ introspective::Class[introspective::msg::Set] -> tsl::Variant
* introspective::Object[introspective::msg::Is] -> bool

Properties:0
Methods   :9

with the following meaning: 

@type  : 'Class name'

The receiver (in this case MyClass) is a type named 'Class name'

+ introspective::Class[introspective::msg::Clone] -> introspective::Message::Receiver*

the '+' sign in first column means that the following method is public (i.e. inheritable) while the rest of the line indicates that the method is a class method responding to a Clone message and returning a pointer to a new receiver. 

 

Every receiver (so class and objects) are also able to modify theyr behaviour adding or removing method and properties.

Joomla templates by a4joomla