<-- back
Ownership
- Member pointers can be marked by one of the keywords
own
or share
but are owned by default.
- For parameters, both keywords can be used again. But they are shared by default.
- For return types, both keywords can be used again. But they are shared by default.
- Local variables take on the type given by the assignment.
- Shared variables can NOT be assigned to owning types.
- Shared variables can be assigned to sharing types. Assigning results in decrementing the reference count of the previously stored shared pointer and incrementing the reference count of the newly assigned pointer.
- Owned variables can be assigned to owning types (or transferred via parameters or return values). Doing so revokes the ownership of the previous scope or object and the new object/scope becomes the owner.
- Owned variables can be assigned to sharing types. Upon assignment, if the
share
keyword is used, the owned pointer revokes all ownership and the pointer becomes a purely shared pointer. Without using the share
keyword, the pointer is assigned the same as a shared pointer.
- After assigning a previously-owned pointer, the pointer becomes NULL.
- If the compiler detects the necessity, pointers are always stored with a reference count and a flag, whether they are owned or not.
- When a pointer is owned, the reference count counts how many shared references there exist.
- When an owned pointer gets deleted and there still are shared references, the runtime system executes an exception.
- When an shared pointer gets deleted, its reference count gets decremented until the counter reaches zero. Then, if it is not owned by anyone, it gets deleted automatically.
- Shared pointers can never become owned pointers again.
- A type with
own
always is implicitely mutable
.
- The keyword
own
as a type means: This variable owns the pointer.
- The keyword
share
as a type means: This variable stores a shared pointer.
- The keyword
own
as an operator means: The ownership of the pointer is transferred to the receyving scope.
- The keyword
share
as an operator means: The ownership of the pointer is revoked and shall never again be owned by anyone.
- Not using any of the two keywords at all means: The ownership stays as it was before. The reference count though is handeled just the same as always.
- Both keyword
own
and share
can only be used as an operator acting upon an owned variable.
- Static variables are nothing but global variables. Ther are defined BEFORE any module definition in the file. The are always owned by the runtime system and can never be un-owned.
- Static variables can be public (embedded programmers and quick and dirty programmers prefer not to be restricted) but it is good practice to hide them. If public access is really needed, it is strongly advised to use a public static function of a specific module to access them if you want to have them available in other modules. Note that mutable must be specified in order to change the object. Always be aware that a global static variable and a public static function is explicitely public, even when using the module as a third party.
NAL:
myStaticObject = MyPointerClass; // auto initialized to nullptr
MyClass = module;
.myOwnMember = MyPointerClass;
.mySharedMember = share MyPointerClass;
.constructor = (mutable this){
myOwnMember = new MyPointerClass();
mySharedMember = nullptr;
}
.getShared = MyPointerClass (this) {
return mySharedMember;
}
.getOwned = MyPointerClass (this){
return myOwnMember;
}
.getSingleton = MyPointerClass (){
if(!myStaticObject)
myStaticObject = new MyPointerClass();
return myStaticObject;
}
.revokeOwned = own MyPointerClass (mutable this){
return myOwnMember;
}
.setShared = (mutable this, MyPointerClass newPointer){
mySharedMember = newPointer;
}
.setOwned = (mutable this, own MyPointerClass newPointer){
myOwnMember = newPointer;
}
{
myGlobalPointer = MyClass.getSingleton();
myPointer = new MyPointerClass();
myObject = new MyClass();
myObject.setOwned(own myPointer);
someSharedPointer = myObject.getShared();
someSharedPointer = myObject.getOwned();
myPurelySharedPointer = share myObject.revokeOwned();
myScopeOwnedPointer = myObject.revokeOwned();
}
C:
struct MyClass{
MyPointerClass* myOwnMember;
const MyPointerClass* mySharedMember;
};
MyClass* _nal_MyClass_constructor(){
this = _nal_alloc(MyClass);
this->myOwnMember = _nal_own(_nal_MyPointerClass_constructor());
this->mySharedMember = NULL;
return this;
}
const MyPointerClass* _nal_MyClass_getShared(const MyClass* this){
_nal_incRef(this->mySharedMember);
return this->mySharedMember;
}
const MyPointerClass* _nal_MyClass_getOwned(const MyClass* this){
_nal_incRef(this->myOwnMember);
return this->myOwnMember;
}
MyPointerClass* revokeOwned(this MyClass mutable){
MyPointerClass* _retValue = this->myOwnMember;
this->myOwnMember = NULL;
return retValue;
}
void _nal_MyClass_setShared(MyClass* this, const MyPointerClass* newPointer){
_nal_decRef(this->mySharedMember);
this->mySharedMember = newPointer;
_nal_incRef(this->mySharedMember);
}
void _nal_MyClass_setOwned(MyClass* this, MyPointerClass* newPointer){
_nal_destroyOwning(this->myOwnMember);
this->myOwnMember = newPointer;
newPointer = NULL;
}
{
MyPointerClass* myPointer = _nal_constructor_MyPointerClass();
MyClass* myObject = _nal_constructor_MyClass();
_nal_MyClass_setOwned(myObject, myPointer);
myPointer = NULL;
const MyPointerClass* someSharedPointer = _nal_MyClass_getShared(myObject);
_nal_decRef(someSharedPointer);
someSharedPointer = getOwned(myObject);
MyPointerClass* myPurelySharedPointer = _nal_MyClass_getShared(myObject);
_nal_decRef(myPurelySharedPointer);
MyPointerClass* myPurelySharedPointer = _nal_pureShare(_nal_MyClass_revokeOwned(myObject));
MyPointerClass* myScopeOwnedPointer = _nal_MyClass_revokeOwned(myObject);
_nal_decRef(someSharedPointer);
_nal_decRef(myPurelySharedPointer);
// myPurelySharedPointer might be leaking if there is a cyclic reference.
_nal_destroyOwning_MyClass(myScopeOwnedPointer);
}
Discussion