| Object Specialization Model | 
   | © Copyright 2009 - 2011 by Miroslav Bonchev Bonchev. All Rights Reserved. | 
   | Open Source License | 
   | Before using the Object Specialization Model you must agree with the Software License. | 
| Abstract | 
| 
The Object Specialization Model extends the Object Oriented paradigm by appending context to objects at the point of their definition. The context is represented by metadata, so that the objects with and without context have the same footstep and performance. However based on the context metadata the compiler is able to locate and decline incorrect assignments. Context definitions have no size and complexity limits and thus a variable with context could encompass large composite meaning. By appending context to objects in the parameter list of fixed number of parameters operators, the Object Specialization Model expands the language syntax function space since prototypes with the same type of parameter(s) but different context are differentiable and unambiguously referable. In the similar way the Object Specialization Model presents a new, third way of function overloading. The Object Specialization Model also helps to maintain more readable code and a more structured model and namespace. The Object Specialization Model however requires a somewhat more typing while programming.
 | 
| Object Specialization Model | 
| 
We consider software modelling in object oriented environment, using C++ in particular.
 | 
It is not unusual for people to wonder why in the law of God lies are forbidden. One possible answer is that in an absolute world lies cannot exist or if they exist in a world then that world is not absolute. This is so because for a lie to exist it requires another lie to maintain it and thus if a lie is introduced then eventually the world becomes entirely self-contradictory. Hence in the world of God, which by definition is complete and omniscient a lie is impossible. Take this affirmation and translate is to the relation between a world that has been modelled by software and the world of the software itself. The software must represent the universe of discourse precisely or if this fails to be the case, then early or late there will appear one or more fundamental contradiction in it, which will make the software eventually impossible to exist (live) - grow. This implies necessity for the software model to be in one to one correspondence with the world that it describes, i.e. is to have no "lies" in it.
  
One of the implications of the above proposition is that names of variables must be precise. Comprehensive namespace however is only possible within comprehensive model. On the other hand comprehensive model is not possible without comprehensive namespace.
  
Suppose all variables in some software are named precisely with the names of entities that they precisely represent. What makes it impossible to use two or more variables of the same type interchangeably but inappropriately? Suppose that there are two Boolean variables representing the values of two unrelated propositions say: "Today is Monday" and "Water flows". Clearly they have nothing in common and must not be confused or mixed, however since the two variables representing the propositions are of the same type it is possible to erroneously assign the value of one of them to the other or use them in the same Boolean expression inappropriately, such as using the incorrect variable in a function call or other. So although the variable names represent some entity precisely errors are possible. These errors if misunderstood and corrected erroneously will lead to failure to maintain bijective representation of the universe of discourse. 
  
Thus we identified the existence of another dimension to each and every variable which is its context. The author hereby proposes the idea to add a new dimension to objects, which would accommodate the information for context of the variable. This information then can be used by the compiler to ensure that the variable is being used only in the correct context, and if used improperly raise an appropriate error. Variables from different contexts could be used cross-context only via appropriate explicit context conversion.
  
The property maintaining the context information must be part of the meta-space, as opposed to part of the object. Thus the context of the object does not in any way alter the physical footstep of the object or its performance. All context information, checks, conversion and other properties and information are maintained explicitly in the meta-space and have no impact whatsoever on the compiled software and its performance.
  
In fact context already exist when considering types. The context of a type is defined by the namespace (if any) where the type is defined or the container (if nested), its ancestors and the overload constructors, methods and conversion operators. Presently context of variables also exist but only at physical level, which can be declaration scope (stack frame), containing class (object) or both. This is why two variables of the same type existing in compatible stack frames can be freely misused. The proposal in this paper is to add logical scope to variables, i.e. context of objects, and thus prevent misuse in the same way as object from incompatible types cannot be misused without explicit conversion.
  
Adding context to a variable must effectively modify the methods/conversion operators of the class of the variable in a way so that there is a consistent behaviour. Ideally there would be native compiler support, where appropriate syntax might be for example:
 | 
bool<~ ContextA ~> bObjectName1;
bool<~ ContextB ~> bObjectName2;
  | 
  
| 
It is possible to achieve variable specialization, i.e. attach context to variables with the facilities that C++ already have, although dedicated native support would be preferable. By using template specialization and inheritance we are able to achieve the required results. Consider the template class definition from Listing 1 below.
 | 
| 
Listing 1. Template class achieving variable specialization using already available C++ facilities.
 | 
template< class classConstitution, class classContext > class specialize : public classConstitution
{
public:
   class Init
   {
   public:
      const classConstitution& obj;
   public:
      explicit Init( const typename classConstitution& obj ) : obj( obj )
      {
      }
   private:
      Init& operator=( const Init& objInit )
      {
         obj = objInit;
         return( *this );
      }
   };
   static Init Initialize( const typename classConstitution& obj )
   {
      return( Init( obj ) );
   }
   specialize()
   {
   }
   specialize( const Init& obj ) : classConstitution( obj.obj )
   {
   }
   specialize( typename const specialize< classConstitution, classContext >& obj ) : classConstitution( *(classConstitution*)&obj )
   {
   }
   
   typename specialize< classConstitution, classContext > operator=( typename const specialize< classConstitution, classContext >& obj )
   {
      __super::operator=( obj );
      return( *this );
   }
   // prohibited to  prevent unwanted assignments.
   // typename specialize< classConstitution, classContext > operator=( typename classConstitution& obj ) { ... }
   }
};
#define as ,
#define by ,
#define of ,
 | 
| 
Figure 1 below depicts the class diagram of the specialize template class.
 | 
| 
Figure 1. Class diagram of the specialize< parameters > template.
 | 
 
 | 
| 
An object from this type specialized with a type that we want to be intrinsic for the object and a second type giving the context is in fact a variable of the intrinsic type specialized with the context type, which is our objective. An object defined and specialized with the help of this template is less attractive than native implementation would be but still gives the required results:
 | 
specialize< bool, ContextA > bObjectName1;
specialize< bool, ContextB > bObjectName2;
  | 
In the template definition above we only allow one directional assignment, which may seem overly strict but as we shall see it is necessary. The problem may seem to be that assignment such as: bObjectName1 = true/false; generates error since the compiler does not know how to assign the reference-able (R) value to the locatable (L) value. Adding the banned operator= resolves this issue (in fact not an issue); however this clears the path for assignments such as: bObjectName1 = bObjectName2;.
  
This would defeat the purpose of the additional abstraction that we aim to introduce. Through the implied conversion to the ancestor type allowed by the public visibility of the superclass, and then through the overloaded assignment operator of the specialiser class the compiler quietly assigns incompatible-by-specialization (but compatible by type) variables, through the common superclass. Thus to break the chain we either have to disable the implied conversion or to remove the compatible function overload, or both. When working with existing code there would be many instances of objects from the superclass already existing in the code as well as functions with parameters of the superclass. Prohibiting the implicit conversion from specialized to non-specialized objects (i.e. to the superclass) would lead to cumbersome programming due the necessity for explicit conversion for every assignment or use of specialized type where non-specialized is expected. On the other hand it is most important to ensure that invalid assignment is impossible. Thus the solution is to maintain public inheritance of the superclass and prohibit all compatible operators and methods. We therefore remove the compatible operator overload and constructor which ensures an error in the assignment: bObjectName1 = bObjectName2;.
  
The removal of the compatible assignment operator however is the reason for impossibility of an assignment of object of the superclass:
 | 
bObjectName1 = true;  // generates error
bObjectName2 = false; // generates error
  | 
| 
We cannot introduce a constructor with appropriate type to initialize the specializer as this will lead to the same problem as with the dedicated operator=, namely bypassing the context-wall which we aim to create. This we introduce the auxiliary type Init and helper function Initialize( ... ) to help the initialization:
 | 
bObjectName1 = specialize< Bool, ContextA >::Init( true );
bObjectName2 = specialize< Bool, ContextB >::Init( false );
// or
bObjectName1 = specialize< Bool, ContextA >::Initialize( true );
bObjectName2 = specialize< Bool, ContextB >::Initialize( false );
  | 
| 
Remark: We do not make distinction between built-in type and user-defined type. For the purposes of this proposal we shall supply a wrapper class to any used build-in type in order to maintain consistency.
 | 
| 
Definition: Context Specialized Type or just Context Type is a type composed by two or more types (possibly context specialized) and is constructed in the metaspace explicitly when declaring an object thus defining its type. The first of these types called constitution-class (or superclass, or type-class), determines the character and behaviour of the object, thus the object "is of" that type. The remaining one or more types called context-class(es) determine the relationships which the object could have, i.e. its context.
 | 
| 
Example: Using classes bool and Colour we define specialized types:
 | 
bool<~ Color ~> boolMyPulloverBlue;
Color<~ bool ~> argbColorSuitable;
  | 
| 
Using the above template implementation:
 | 
specialize< Bool, ContextA > bObjectName1( specialize< Bool, ContextA >::Initialize( true ) );
specialize< Bool, specialize< ContextA, ContextB > > bObjectName1( specialize< Bool, specialize< ContextA, ContextB > >::Initialize( true ) );
  | 
Remark: The definition of Context Specialized Type does not in any way restrict the complexity of the constitution and context classes.
  
Consider the task to place the type of a file in a string. Some software architects may take the approach to specialize a type i.e. derive a type e.g.:
 | 
class FileTypeDescription : public string
{
   // do almost nothing here, most work is in the base class
};
 | 
| 
In practice almost all architects will simply use the string class just as it is. To use the context specialization methodology however we can create an auxiliary type with an absolutely empty content e.g.:
 | 
namespace sX
{
   class FileTypeDescription { /*nothing*/ };
};
 | 
| 
Then simply context specialize the string object with it, achieving the desired result:
 | 
specialize< string, sX::FileTypeDescription > strType( specialize< string, sX::FileTypeDescription >::Initialize( TEXT( "File type" ) ) );
  | 
| 
To improve readability we define pre-processor syntax definitions for appropriate prepositions such as "as" and "by" with coma, thus from now on we shall use the appropriate preposition instead of coma in order to improve readability. It is a good practice to declare empty context-classes declared for the sole purpose to help constituting of Context Specialized Types in a dedicated namespace, thus separating them from the rest of the model. By convention this name space is called sX. Clearly using auxiliary empty context-classes is wrong when there are proper non-sX classes available in the model, which could be used as context-classes, or when an appropriate context could be assembled from them. For example suppose that the non sX-classes FileType and Description exist. Then we could do the same declaration as above as follows:
 | 
specialize< string as specialize< FileType by Description > > strType;
  | 
| 
If there are classes File, Type and Description existing in the model, then we could construct the context:
 | 
specialize< string as specialize< Description of specialize< Type of File > > > strType;
  | 
| 
In a comprehensive model most classes would exist as non sX, and very few sX classes will be required. When using multi-layer specialization as in the above two examples there may rise some disputes as to which class should be constitution-class and which context-class, e.g. should we have specialize< FileType, Description > or specialize< Description, FileType >. Consider the following prototype:
 | 
Pair< specialize< Integer as Quotient >, specialize< Integer as Reminder > > Integer::operator /( Integer iDividend, Integer iDivisor );
  | 
| 
Now one need to define classes: class Quotient { … } and class Reminder { … } for this declaration to be meaningful. On the other hand Quotient and Reminder are integers, so there is a legitimate question whether defining class Quotient : public Integer { }; and class Reminder : public Integer {};, or even better template< class T> class Quotient : public T {}; and template< class T> class Reminder : public T {}; is not better than using the Object Specialization Model? Defining Quotient and reminder as templates may seem similar to the original declaration, but they are clearly very different: specialize< Integer as Quotient > specializes an Integer variable as quotient, that is limits its external friends and field of connections. The other however specializes the internal nature of the type Quotient. The alternative to the original declaration is then: inline Pair< Quotient< Integer >, Reminder< Integer > > operator /( Integer iDividend, Integer iDivisor );. At first glance this declaration will have immediate consequences similar to the original one, provided that casting operators and implicit constructors are unavailable, but in fact this is a wrong way to go. The reason is that the type Quotient is not restricted to only the whole part of division, but in a larger generalization (besides general homonyms). Quotient can also be a set, group, space, etc, and template specialization cannot truncate this larger generalized type to the small reminder from division case. Further Quotient< double > is a self-contradictory statement however there is no intrinsic way to prohibit such declaration, while Reminder< double > is perfectly all right. Quotient and Reminder are abstract entities and when defined as types required careful attention. Thus the specializer approach above is the correct one in this case. The analysis of this model could be further extended but will be omitted here. The most important consideration as always is to maintain bijective relation between the software model and the Universe of Discourse.
 | 
| 
Suppose there is an enumerator defined as:
 | 
enum Result
{
   Success   = 0,
   Failed      = 1,
   Exception = 2
   // ...
};
 | 
| 
This scenario is not different than an integer int< Width > when there is a native support for the Object Specialization Model.
 | 
Result<~ sX::Item ~> resultItem1; 
Result<~ sX::Item ~> resultItem2;
  | 
| 
However if we are using the substitute methodology we will have to define a class for each enumerator, which would include the native enum and operate on its behalf. Use of template specialized with the enumerator or a declaration map propagating the native enumerator might be useful to simplify the task in a generic way.
 | 
| 
The Object Specialization Model brings several advantages to software that implements it:
 | 
| 
1. Safer code – the object specialization model prevents use of incorrect variables when they are from the same type but different contexts. Consider the following example form a commercial application:
 | 
bool Save( const bool bKeepOnTopC,
                    const bool bKeepOnTopO,
                    const bool bUseFullPath,
                    const bool bPreviewFile,
                    const bool bShufflePlay,
                    const bool bPlayNextDir,
                    const bool bLoopDirDirs ) const throw();
 | 
| 
Such functions with large list of parameters are not unusual in professional software development. Regardless whether this large list of parameters is due to bad design or is indeed intrinsic for the function, the possibility for an error using the incorrect Boolean value is there. To prevent from errors the software engineers are required to invest extra effort. Using the object specialization model we transform the above function to a safe one as follows:
 | 
bool Save( const specialize< Bool as sX::OnTopCompDlg > bKeepOnTopC,
                    const specialize< Bool as sX::OnTopOpenDlg > bKeepOnTopO,
                    const specialize< Bool as sX::UseFullPath  > bUseFullPath,
                    const specialize< Bool as sX::PreviewFile  > bPreviewFile,
                    const specialize< Bool as sX::ShufflePlay  > bShufflePlay,
                    const specialize< Bool as sX::PlayNextDir  > bPlayNextDir,
                    const specialize< Bool, sX::LoopDirDirs  > bLoopDirDirs ) const throw();
 | 
| 
In the next example we will protect the FILETIME members of a structure from the same type of error.
 | 
struct FileData
{
   unsigned __int64 uiFileSize;
   DWORD dwAttributes;
   specialize< FILETIME as sX::CreationTime   > ftCreationTime;
   specialize< FILETIME as sX::LastAccessTime > ftLastAccessTime;
   specialize< FILETIME as sX::LastWriteTime  > ftLastWriteTime;
   string strFilepath;
};
 | 
| 
2. Descriptive self-explanatory code – the definition of a context specialized object it is not only the name of the object but also the Context Type which carries additional information for the meaning and purpose of the variable. Thus the code becomes much more readable and meaningful. In addition the type information, i.e. the constitution and context classes’ information is also displayed by the Intelli-sense of the IDE and also in the watch windows of the debugger making writing and debugging of code more efficient.
 | 
| 
3. Expanding and structuring the namespace/type-space - this is an architectural benefit for the particular software model being developed. Because of the context specialization, software architects now have more points and relationships to base their models on and thus should have less number of failures in their attempts to achieve bijective model. Generally, models always fail to be bijective and that is why fresh new versions of software are developed. Consider the multibillion investments in Windows XP and the complete rewrite done for Windows 7.
 | 
| 
4. Language function space expansion. Suppose the class:
 | 
class MyClass : public MyClassParent
{
   // ...
   virtual bool operator == ( const string& strFileNameToCompare ) const;
};
 | 
| 
is well defined and working on a whole hierarchy of types, with multiple instantiations and calls to the above comparison operator. The passed as parameter string is interpreted as a filename and is used to compare the content of the file with the content of the particular object invoking the method. Suppose that later one needs to have another operator with the same prototype:
 | 
virtual bool operator == ( const string& strStringToCompare ) const;
  | 
| 
but this time they want to compare the actual string with the content of the object. However since the prototype is already used the new function cannot be implemented with the same prototype. Traditionally the solution would be to add another parameter, thus changing the prototype, and clarifying to the compiler which function we would like it to call. It is clear that such an approach is crude, but in this particular case it is not even possible since operator== can have only one parameter. There are also other possible crude solutions, requiring flags, initializations, definition of special unwanted types, etc. The Object Specialization Model however presents quick and elegant solution. The solution of this problem using the suggested methodology is to specialize the parameter of the function as follows:
 | 
class MyClass : public MyClassParent
{
   // ...
   // original declaration - could be also kept if wanted.
   // virtual bool operator == ( const string& strFileNameToCompare ) const;
   // modified original declaration.
   virtual bool operator == ( const specialize< string as sX::FileName >& strFileNameToCompare ) const;
   // The newly added function.
   virtual bool operator == ( const specialize< string as string >& strStringToCompare ) const;
};
 | 
| 
Now, should one desire they could specialize the parameter as they wish, including multi-level (nested) specialization if the universe is discourse that they work with requires it.
 | 
5. Context overloading – Inspired by the above methodology the Object Specialization Model allows a new third way of method overloading. The two other methods are:
  
a) Overwriting – when using polymorphic functions with the same prototype;
  
b) Overloading – when using functions with the same type but different parameter list.
  
And now the third way: 
  
c) Context overloading – works on both polymorphic and non-polymorphic functions with the same name and the same parameter list where only the context-class of one or more parameters is different than that of any other overload. Example: the following three context-overloads are well defined overloads which will be distinguished by the compiler and called as appropriate according to the type of the second parameter of the call.
 | 
void MyClass::MyFunction( int, specialize< string, sX::FileName >& );
void MyClass::MyFunction( int, specialize< string, sX::FolderName >& );
void MyClass::MyFunction( int, specialize< string, string >& );
  | 
| 
We finish the Object Specialization Model with a note that in some cases specialization may be needed on a verb as opposed to a noun. That is the constitution-class represents a verb or other type of entity instead of a noun as usual. The same is also true for the context-class. Given the ability to construct multi-layer (nested) Specialization Types this implies that an object could have Specialization Type which (literally) (re)presents a complete or partial sentence and if necessary even a paragraph, chapter or novel.
 | 
| 
  
 | 
Miroslav B. Bonchev
  4-th May 2011  London, England |