Objects
DQ objects are reference types with fields, methods, constructors, destructors, properties, inheritance, and virtual dispatch.
Declaration
object OCounter:
private
value : int = 0
public
function Inc():
value += 1
endfunc
function Value() -> int:
return value
endfunc
endobj
Members can be grouped with visibility labels such as public and private.
The current codebase commonly uses these labels inside object declarations.
Allocation
Object variables are references. A reference may be null.
var obj : OCounter = null
Use new for heap allocation.
obj = new OCounter()
Use delete to destroy a heap object and release its storage.
delete obj
Embedded allocation uses <-.
var local_counter <- OCounter()
var global_counter <- OCounter()
Embedded objects live in the containing storage location, such as a local stack frame, global data, or another object.
Constructors and Destructors
*Create is the constructor. *Destroy is the destructor.
object OData:
value : int
function *Create(initial : int):
value = initial
endfunc
function *Destroy():
// cleanup
endfunc
endobj
Constructors can be overloaded with [[overload]].
object OText:
function *Create() [[overload]]:
endfunc
function *Create(text : strview) [[overload]]:
endfunc
endobj
Methods
Methods are declared inside an object. They can also be implemented outside the object by qualifying the function name.
object OThing:
function Run()
endobj
function OThing.Run():
// ...
endfunc
Inside a method, object fields and methods are available without a self.
prefix.
function OCounter.Inc():
value += 1
endfunc
From the object methods variables and functions outside of the object cannot be accessed without full namespace qualification.
Method body use statements can blend-in namespaces so they can be used without qualification.
function OCounter.Print()
@print.PrintLn('counter={}', value) // @print. can be used to access PrintLn()
@.PrintLn('counter={}', value) // "@." for access everything that available in the current module
use print // now the symbols in @print are available without qualification
PrintLn('counter={}', value)
endfunc
Inheritance
Objects support single inheritance.
object OBase:
function Count() [[virtual]]:
endfunc
endobj
object OChild(OBase):
function Count() [[override]]:
inherited
endfunc
endobj
inherited calls the inherited implementation of the current method.
Virtual Methods
Virtual methods are marked with [[virtual]]. Overrides are marked with
[[override]].
object OBase:
function Write(text : strview) [[virtual]]:
endfunc
endobj
object OChild(OBase):
function Write(text : strview) [[override]]:
endfunc
endobj
The compiler also recognizes [[abstract]] and [[final]] in object method
contexts.
Dynamic Casts
Object references can be dynamically cast with TryCast or with tryfrom.
var base : OBase = child
var child2 : OChild = TryCast(OChild, base)
var child3 : OChild tryfrom base
If the value is not compatible with the requested object type, the result is
null.
Properties
Properties expose field-like syntax backed by fields or methods.
object OBox:
private
stored : int = 0
function GetStored() -> int:
return stored
endfunc
function SetStored(value : int):
stored = value
endfunc
public
property value : int read GetStored write SetStored
endobj
A property must have at least a read or a write accessor.
Field-backed properties are also supported.
property direct : int read stored write stored
Properties are used like fields.
box.value = 10
box.value += 1
PrintInt(box.value)
Read-only and write-only properties are possible by omitting the opposite accessor.
property readonly : int read GetStored
property writeonly : int write SetStored
Indexed properties place an index signature before the property result type.
property item : [index : int]int read GetItem write SetItem
property cell : [row : int, col : int]int read GetCell write SetCell
Indexed accessors must be methods. A getter receives the index arguments and returns the property type. A setter receives the index arguments followed by the new value.
An indexed property can be marked default. The default indexed property is
used when the object itself is indexed.
object OJson:
...
property child : [int]OJson default read Child
endobj
function Test():
var firstchild : OJson
var rootobj = new JSon()
rootobj.LoadFromFile('test.json')
firstchild = rootobj[0]
endfunc
Properties themselves are not addressable, but values returned by a property keep their normal semantics. For example, a property returning an object reference can be used to access that object's members.
Object Function References
Method reference types use of object.
type FObjText = function(msg : cstring) of object
An object method reference contains both the method and the object instance. Virtual functions resolved at assignment.