Access Control (draft)
Haxe classes fields and methods have two levels of access control :
public: this field is always accessibleprivate: this field can only be accessed by this class and its subclasses (this is the equivalent ofprotectedin Java for instance)
However when writing a library or a complex application you might want much more fine-grained control on which other classes are allowed to access your private fields. Other languages have specific keywords to provide same-package-access or namespaces, let's see how it can be done with Haxe.
Giving Access
If you want to give access to the private fields of your class to another class/package you can simply add @:give metadata in front of your class declaration, such as the following example shows:
package my.pack; @:allow(my.pack) class MyClass { private var foo : Int; }
This will give access to all private fields of MyClass to all the classes in the package my.pack (and its sub-packages).
You can also give access to multiple packages by adding several @:give or only give access to a specific class (and its subclasses) by specifying the complete class name, see below for an example :
package my.pack; @:allow(my.pack) @:allow(my.other.pack) @:allow(my.SpecificClass) class MyClass { private var foo : Int; }
Note : you can also give access to an interface, then all classes implementing it will get access to your class privates.
Getting Access
While @:allow should be enough for most of the users, it does not cover all the cases.
Let's say for example that you are using a library or some other code that for some reasons you can't modify. In that case, accessing to private fields is not possible since you can't add the necessary @:allow declarations.
You can then get access to a given class (or whole package) private fields by using @:access metadata :
@:access(my.pack.MyClass) class Main { }
One might argue that this is intended by the original code author : if the field is private, you shouldn't access it since it is an implementation-specific behavior that might change if the library is updated, or many other good reasons.
These are good reasons, and you should really follow these rules 99% of the time.
However there's still this 1% left when you would actually like to access another class private fields without this right being explicitly given to your class. This can be for debugging purposes, this can be for any other reason : Haxe philosophy is to have confidence that the developer know what he is doing, especially in that case since it's explicitly declaring it.
You can of course have several @:access declarations in the same way it is possible for @:allow, or specify a whole package which you want to be able to access classes privates fields :
@:access(my.other.pack) @:access(my.pack.MyClass) class Main { }
Per-field access control
Both @:allow and @:access are also possible to be declared in front of a single field.
You can give access to only some specific private fields of your class :
class MyClass { // only give access to this specific private field @:allow(my.pack) private var foo : Int; }
You can also only get access from within only specific methods of your class :
class Main { // only get access to MyClass private fields in this method @:access(my.pack.MyClass) function doSomethingSpecial() { } }
On the choice of Metadata
This access-control language feature uses the Haxe metadata syntax instead of additional language-specific syntax. Here's some reasons why :
- additional syntax often complexify the language parsing, and also adds (too) many keywords.
- additional syntax requires additional learning by the language user, whereas metadata syntax is something that is already known
- the metadata syntax is flexible enough to allow extension of this feature
- the metadata can be accessed/generated/modified by Haxe macros
Of course, the main drawback of using metadata syntax is that you get no error report in case you misspell either the metadata key (@:acesss for instance) or the class/package name.
But since for this feature you will get an error when you try to access a private field that you are not allowed to, there is no possibility for silent error.