4 \$class and \$struct
There are 5 class types:
- $struct
- $class
- $adt
- $mixin
- $model
The Xc++ language allows for reflecting classes and structs using $class and $struct.
Public modifier
For example
$struct+ X
{
$int32 x;
};
The public modifier (+) means that X is public - so it is:
- reflected (an object instance of a ReflectedClass is defined which represents information about the class which is available at run-time)
- registered (the
ReflectedClassinstance is registered in the ReflectedClass registry) - exported (if
Xis defined in a Windows dynamic link library then the symbols are exported to allow for usingXfrom other libraries and executables)
The public modifier (+) cannot be used on a generic type such as a $mixin, or else Xcpp gives the error
'+' modifier not permitted on $mixin
The public modifier (+) also cannot be used on nested classes or structs.
Example
Here's a more complicated example:
$class+ C <<dc>> isa ceda::IObject :
Base1, public Base2, private Base3
model SomeModel
mixin [Mixin1 Mixin2] Base4, protected Base5 : [1,2,3,foo(x)]
{
};
dc is a directive which determines whether a default constructor is defined.
Implementing an interface
A class or struct can declare it implements an interface using isa. For example:
$class X isa IObject
{
};
Referenced base model
A class can reference a base model by name.
In the following example class X references its base model M by name:
$model M {};
$class X : model M {};
Note that M must be a pure model
(a class with an embedded model is not sufficient to be referenced in this manner).
Anonymous models in the mixin chain
A class can define any number of anonymous models in its mixin chain. For example:
$class X : mixin
[
model
{
int32 x;
float64 y;
}
]
This model is called an anonymous model mixin.
Models
Models can be free standing
$model Point
{
int32 x;
int32 y;
};
They can be inherited in a $class
$class X :
model
{
int32 x;
}
{
};
They can be embedded directly
$class X
{
model
{
int32 x;
}
};
More examples
$class X {};
$class X { $model{} };
$model M {};
$class X : mixin[M1 M2] {};
$mixin X {};
$mixin X<typename T> {};
$mixin X { $model{} };
$class X : model {} {};
$class X : model M {};
$mixin X : model {} {};
$mixin X<typename T,int N> : model {} {};
$mixin X : model M {};
$class X : mixin [M] {};
$mixin [model{}] {};
$mixin X : mixin [M] {};
$class X : mixin [model{}] {};
$class X isa ceda::IObject {};
$class X isa ceda::IPersistable {};
$class X : model{} mixin [model{}] {};
$class X : model{} mixin [model{}model{}] {};
$class X isa ceda::IObject : model{} mixin [model{}model{}] {};
| example | |
|---|---|
| pure model | $model M {}; |
| base model | $class X : model {} {}; |
| referenced base model | $class X : model M {}; |
| nested model | $class X { $model{} }; |
| embedded mixin model | $class X : mixin [model{}] {}; |
| referenced mixin model | $class X : mixin [M] {}; |
Strict versus non-strict types
Xcpp imposes the use of platform independent types in certain cases. If a class is reflected then its members must have platform independent types. We call this a strict class.
Restrictions on pure models
A pure model is quite restricted:
- It is always implemented using a C++
structnot aclass isacannot be specified to indicate that it implements an interface. It cannot even implementIObject- Pure models cannot have base classes, base models, referenced base models or mixin chains
- Pure models can optionally have a default constructor defined, but no other methods can be defined
- Pure models cannot have
$dep,$indepmember variables or$cachefunctions $evictcannot be used inside a pure model
The range of release numbers for which a field in a model exists in the schema
For each field in a model a half open interval [r1,r2) of integer release numbers represents the set of release numbers for which the field exists in the schema.
We use r2 = -1 to indicate that the field hasn't been dropped in the latest release.
If there is no $schema {...} section then for each model field we have r1 = 0 and r2 = -1. This represents "added but not dropped".
todo: move into description of parser
During the parsing of the $schema {...} section we assume the following
- A field that hasn't been added yet has both r1 = -1 and r2 = -1
- A field that has been added but not dropped has r1 >= 0 and r2 = -1
- A field that has been added and dropped has r1 >= 0 and r2 >= 0 and the range of releases for which the field exists in the schema is [r1,r2)
After parsing the $schema section, it should never be the case that r1 = -1. However it possible for r2 to be -1 to indicate that the field hasn't been dropped in the latest release.