The following class allows for an object to be represented in a database having an int32
member.
$struct+ X isa IPersistable
{
void Serialise(Archive& ar) const
{
ar << x;
}
void Deserialise(InputArchive& ar)
{
ar >> x;
}
int32 x;
};
In this case an embedded model is not used, so the following features aren't available on the members:
One possible reason for not using a model is to allow for sites to have divergent copies of the object. However, that is often better achieved by using objects with models in another working set which is not synchronised in the first place.
Often it makes sense to define an IPersistable
class without a model because it's immutable,
and uses the <<rod>>
directive to declare it as a ROD (Replicate on Demand)
object type.
In the following case a JPeg image object persists as a vector of bytes. This can be decoded to
provide an image.
The buffer would only be updated in the transaction that created the original instance of the
JPeg
object. After that it would never be changed.
When these objects are used in a WorkingSet
their initial state is serialised
when they are replicated to other sites.
$struct+ JPeg <<rod>> isa IPersistable
{
void Serialise(Archive& ar) const
{
ar << buffer;
}
void Deserialise(InputArchive& ar)
{
ar >> buffer;
}
xvector<octet_t> buffer;
};
Now we have an IPersistable
class with a model:
$struct+ X isa IPersistable
model
{
int32 m;
}
{
};
The plan is to support the following syntax:
$object+ X
{
int32 m;
};
In this case a model is used, so the following features are available on the members:
The member variable m
has assignment semantics. Operations on m
must be
pure assignments, so for example you can't use m++
to increment m
, or
m *= 2
to double the value of m
.
Let x
be a variable of type X
.
The following read of x.m
invokes the DGS read barrier on x.m
.
If this is done while calculating a dependent variable then a dependency edge
from x.m
to the $dep
variable is created.
int32 y = x.m;
If x
is a persistent object under the Universal Tree in a WorkingSet
then the following assignment to x.m
generates an assignment operation
which can be propagated to peers over a network connection in order to apply the same
assignment on a replica of the WorkingSet
.
x.m = 10;
This assignment to x.m
also invokes the DGS write barrier on x.m
. This may cause
the dependents of x.m
to be invalidated.
Attempting any of the following updates to x.m
will produce compiler errors.
++x.m;
x.m++;
x.m += 2;
x.m -= 2;
x.m *= 2;
x.m /= 2;
x.m %= 2;
On Windows you get error C3892: 'x': you cannot assign to a variable that is const
.
Unfortunately this isn't an ideal error message, but it is to be expected given the fact that Xcpp
is a rather lightweight preprocessor and a standard C++ compiler is doing a lot of the error checking.
The basic types
bool
,
int8
,
int16
,
int32
,
int64
,
uint8
,
uint16
,
uint32
,
uint64
,
float32
,
float64
,
char8
,
char16
default to assignment semantics.
This means they can only be updated using assignment operations, and under Operational Transformation conflicting concurrent assignments to the same variable are resolved by choosing one of the assignments as the "winner" (this is based on site identifier comparisons).