A resource Type can hide its storage and release what it owns through the
ordinary Delete object command. These are Extended language features.
Type Buffer
Private Field bank:Int
Private Field capacity:Int
Private Method New(bytes:Int)
Self.bank = CreateBank(bytes)
Self.capacity = bytes
End Method
Method Delete()
; Detach the owned handle before releasing it.
Local ownedBank:Int = Self.bank
Self.bank = 0
If ownedBank <> 0 Then FreeBank ownedBank
End Method
End Type
Function CreateBuffer:Buffer(bytes:Int)
If bytes <= 0 Then RuntimeError "Buffer capacity must be positive"
Return New Buffer(bytes)
End Function
Function BufferSize:Int(buffer:Buffer)
Return buffer.capacity ; Same-module free functions have private access.
End Function
Inside a named Module, its free functions, other Types, and included files
can access these private members. An importing program uses
Buffers.CreateBuffer(64), Buffers.BufferSize(buffer),
and Delete buffer. It cannot read buffer.bank or call
New Buffers.Buffer(64). A dotted submodule is a separate module.
Without a Module declaration, the main program and its Includes form one scope.
Unprefixed members are public. Private Field x:Int, y:Int makes
both fields private; the following declaration returns to the public default.
Use Private Method for helper methods and Private Method New
for construction through a factory. Private Types may appear in private fields
and methods, but cannot leak through public signatures. Privacy is not encryption:
source and debugger inspection remain available.
Declare at most one Method Delete(). It takes no parameters or
return annotation and cannot be Private. Bare Return exits cleanup;
returning a value is an error. It is invoked only by deletion, never by
object.Delete(), and is not an Interface method. Deletion through
an Interface still invokes the concrete object's destructor.
The destructor runs synchronously before fields are cleared. Self, its
private helpers, and aliases remain usable during the body. After it finishes,
all aliases compare equal to Null. Deleting Null or an already deleted alias
does nothing. Recursive deletion through an alias does nothing while that object
is destroying; direct Delete Self in a destructor is an error.
Objects are Constructing until field initialisation and Method New complete. Deleting or reordering a constructing object is an error, including through an alias. A constructor's bare Return completes construction normally. Objects remain visible to constructor-time enumeration. A failed constructor has no user-cleanup guarantee.
Destroying objects are excluded from newly started Each, First, Last, Before, and After traversal. They cannot be reordered with Insert. Ordinary Each retains its existing mutation rules. Delete Each instead retains a snapshot of fully constructed live objects at entry, in list order. A destructor may delete siblings, reorder survivors, or create objects: each original entry is deleted at most once, and new objects are excluded. Nested Delete Each skips currently destroying objects.
Delete only what the object owns. Clear ownership links before deleting child objects, then delete their containers. Deleting a List, Map, Set, Queue, Stack, or object-valued field storage releases references; it does not implicitly delete the referenced objects. Borrowed game entities and other resources remain the caller's responsibility. Integer runtime handles still need their Free or Close command inside cleanup.
Leaving scope, replacing a reference, removing a collection entry, End, program fall-through, and runtime shutdown do not invoke user destructors. Explicitly delete owners before shutting down the systems they use.
A destructor cannot cancel deletion. On RuntimeError or End, committed receivers are finalised and temporary deletion references are released, then the original signal propagates. The rest of that destructor and any remaining Delete Each callbacks are not run. Crashes and unrecoverable WebAssembly traps have no cleanup guarantee. Keep saving, committing, or other fallible business operations explicit, outside the destructor.
Workers cannot allocate or delete Types with destructors, use Delete Each on them, or delete Interface references. Raw worker cleanup invokes no callbacks.
See the complete resource cleanup example, constructors, modules, and Delete.