Version 5 (modified by hopscc, 11 years ago) |
---|
Properties
Introduction
Properties provide a way to get and set values that characterize an object. These values can be private fields or entirely code generated or synthesized. These give class members that provide a mechanism to read, write, or compute the value of a real or virtual private field. Properties can be used as if they are public data members, but the private field access can be mediated by code
Properties combine aspects of both fields and methods. To the user of an object, a property appears to be a field, accessing the property requires the same syntax. To the implementer of a class, a property is one or two code blocks, representing a get accessor and/or a set accessor. The code block for the get accessor is executed when the property is read; the code block for the set accessor is executed when the property is assigned a new value. A property without a set accessor is considered read-only. A property without a get accessor is considered write-only. A property that has both accessors is read-write.
Cobra provides some shortcut syntax for the most common case - property access to a private backgrounding variable and for marking readonly (get) and writeonly (set) properties clearly.
A class properties can be indexed as well as single variable access.
Syntax
pro <Name> from var [ is <AccessModifier> ] (1) pro <Name> from <VarName> [ is <AccessModifier> ] (2) pro <Name> from var [ as <Type> ] [ is <AccessModifier> ] [ = <InitExpr> ] (3) pro <Name> [as <Type>] [is <AccessModifier> ] (4) [<Attribute>] [<DocString>] [ test <Testblock> ] [ get <GetBlock> ] [ set <SetBlock> ] # shortcut: readonly properties get <Name> from var (1) get <Name> from <VarName> (2) get <Name> as <Type> is <AccessModifier> (3) get <Name> [as <Type>] [is <AccessModifier> ] (4) [<Attribute>] [<DocString>] <GetBlock> # shortcut: write-only properties set <Name> from var (1) set <Name> from <VarName> (2) set <Name> as <Type> is <AccessModifier> (3) set <Name> [as <Type>] [is <AccessModifier> ] (4) [<Attribute>] [<DocString>] <SetBlock>
- declare a property name mapping onto an existing declared (possibly private) backing variable named similarly to the property name.
Either the backing is named the same as the property name or has a leading single or double underscore prefix
The properties type is the same as the backing variable, the access modifiers are defaulted or optionally specified. - declare a property name mapping onto the existing declared named backing variable (<VarName?>).
The properties type is the same as the backing variable, the access modifiers are defaulted or optionally specified. - declare a property name mapping onto an implicitly created private backing variable.
Either the Type or an initialising expression must be given to type the backing variable,
Access modifier may be explicitly specified or defaults. - Full Property form:
must specify property type unless want type dynamic, optionally specify access modifiers and get and set mediating code.
If property is declared abstract or is inside an interface then no body (get set blocks ) needed
otherwise there must be one or both of the set-block or get-block clauses
If no Type specified then property is of type dynamic
In a SETBLOCK, any assigned value is accessed through a synthesized variable 'value'.
For all the above
"is <AccessModifier>" can be on the same line or the next. (see AccessModifiers )
wiki:Attributes and a wiki:Docstring? can be optionally provided ( indented on following lines).
A (single) indexed property can also be specified by providing a paramlist enclosed in square brackets for the property name.
Compared to Methods
- Methods can take parameters.
- In practice, methods are not systematically enumerated and invoked.
- Methods may perform substantial calculations and/or I/O.
- Methods are about actions and computations; properties are about inspection or characteristics.
Examples
# The vars are already declared so use "... from var": class Person1 var _name as String var _age as int cue init(name as String) base.init _name = name pro name from var """ The "from var" indicates that the type of the property, as well as its value, is taken from the class variable with the matching name (underscore + property name or underscore + underscore + property name). When you later want to add code for this property, just chop off the "from var" and write the full property (pro foo as Type; get ...; set ...) """ pro age from var # If the underlying variable name is different than the property name, # you can specify that name instead of "var": class Person2 var _name as String cue init(name as String) base.init _name = name pro nombre from _name # properties and their backing vars are declared in one line: class Person3 cue init(name as String) base.init _name = name pro name from var as String pro age from var as int # Give an initial value to the declaration to infer the data type. class Person3 pro name from var = '' # inferred as String pro age from var = 0 # inferred as int # Full property form mapping to backing variable class Person4 var _name as String pro name as String """ The name of the person. Setting the name trims preceding and trailing whitespace from the value. """ get return _name set # `value` is an implicit argument in all property setters: _name = value.trim # Properties can be read-only: class Person6 cue init(name as String) base.init _name = name get name from var as String get lowerName as String return _name.toLower # Properties can be write-only: class Person7 cue init(name as String) base.init _name = name pro name from var as String set internalName from var as String def toString as String is override return 'Person7(name=[.name]. internal=[_internalName])' #indexer class Test pro [i as int] as int get return i*i set pass def main is shared Test().check t = Test() assert t[3] == 9 def check assert this[1]==1 assert this[2]==4 assert this[-3]==9 this[1] = 5 this[2] = 6 assert this[1]==1 assert this[2]==4