Properties
Properties are a specific way to declare class fields, and can be used to implement several kinds of features such as read-only/write-only fields or fields accessed through getter-setter methods.
Here's a property declaration example :
class C { public var x(get,set) : Int; function get_x(){ return 123; } function set_x(value){ doSomethingWith(value); return 123; } }
The values for get and set can be one of the following :
- a "get" or "set" keywords, which means the corresponding method must exist (in our example these are "get_x" and "set_x" functions)
nullif the access is restricted from anywhere but its class' methods (see more below)defaultif the access is a classic field accessdynamicif the access is done through a runtime-generated methodneverif the access is never allowed, not even by means of Reflection
Sample
Here's a complete example :
class C { public var ro(default,null) : Int; public var wo(null,default) : Int; public var x(get,set) : Int; public var y(get,never) : Int; // here y should always equal x public var z(default, set) : Int; private var my_x : Int; private function get_x():Int { return my_x; } private function set_x( v : Int ):Int { if( v >= 0 ) my_x = v; return my_x; } private function set_z( v : Int ) : Int { return z = v; } }
Using property declarations, we declare five public fields in the class C :
- outside the class code, the field
rois read only - outside the class code, the field
wois write only - the field
xis accessed through a pair of getter/setter methods - the field
ycan never be set, not even from code within the same class - the field "z" calls the method "set_z" when "z" is set
For instance, the following two functions are equivalent, although the methods get_x and set_x are private and then can't be accessed directly as in f2 :
var c : C; function f1() { c.x *= 2; } function f2() { c.set_x(c.get_x()*2); }
Important Remarks
Getter and setter methods only work if the type of the class is known. There is no runtime properties handling, so for instance the following code will always trace null since the method get_x will never be called :
var c : Dynamic = new C(); trace(c.x);
The same result will come from trying to use a property with a getter method from a template.
Similarly, read-only and write-only properties will be both readable and writable using a dynamic variable since the type of the class is unknown.
Also, please note that you have to return a value from the setter function. The compiler will complain otherwise.
Dynamic Property
The additional dynamic access can be used to add methods at runtime, on the condition that the containing class implements Dynamic. When a dynamic field x is accessed for reading, the get_x method is called, when accessed for writing the set_x method is called :
class C implements Dynamic { public var age(dynamic,dynamic) : Int; public function new() { } } class Test { static function main() { var c = new C(); var my_age = 26; Reflect.setField(c,"get_age",function() { return my_age; }); Reflect.setField(c,"set_age",function(a) { my_age = a; return my_age; }); trace(c.age); // 26 c.age++; // will call c.set_age(c.get_age()+1) trace(c.age); // 27 } }
Null Property
Unlike initial expectations, null setter specification does not deny all access to the property, as is evidenced with the following example, which indeed succeeds to set the propertys value from within any class' own method(s):
class Main { static function main() { var foo = new Foo(); foo.prop = 1; /// Naturally, fails - write access denied from here. Foo.set_prop_value(foo, 1); /// Succeeds. } } class Foo { static public function set_prop_value(foo: Foo, value: Int) { foo.prop = value; /// Will actually set the value of 'prop' indeed. } public var prop(default, null): Int; public function new() { } }
So, unlike specifying the setter as 'never' (more on that below), 'null' only restricts access from outside the class definition scope, i.e. all scopes eligible for "public" access only. If you need strictly read-only properties, regardless access context, use 'never'.
Never Property
This property non-access specifier can be useful in a number of cases. Below is an example where the number of stored List items is returned by the numItems property. Of course, the return value should always be read from the List and never be set explicitly..
class Container { private var items : List<Item>; public var numItems( get, never ) : Int; function get_numItems() : Int { return items.length; } public function new() { items = new List(); items.add( new Item() ); items.add( new Item() ); } }Now, if called after adding the items in the constructor, both
numItems = 3; and Reflect.setField(this, "numItems", 3); would fail because of the never access specified. On the other hand, if null was specified instead of never, the compiler would have allowed the Reflect call. This could mislead the developer into property abuse.
«« Iterators | Optional Arguments »»