This section describes how various forms of invariance can be expressed.
The 'final
' keyword generally expresses invariance in which entity a name refers to. To declare an entity final, the keyword final can be placed before its declaration. One thing to note is that pattern return values are implicitly final. A pattern invocation can't be used on the left hand side of an assignment. For this reason return types cannot be declared final.
access-modifier final name :super-type :interface-1, interface-2 ... (access-modifier final param-name :param-type, ...)-> return-type
{
pattern-body
}
An entity of a named type can normally be assigned to a different value after its declaration. When an such an entity is declared final it can't be assigned to another value later. Final doesn't prevent the value from being modified if it is an object. That is to say that the name may not be assigned to another object value, but that object may have its members changed. Final may also be used on method parameters to indicate that the parameter will not be changed after invocation (in the pattern body) to refer to a different entity.
Entities of an anonymous type can't normally be assigned to, however if they are patterns they may be virtual. When the final modifier is applied to pattern it indicates that the pattern may not be overridden. This modifier can be used even if the pattern is itself overriding a pattern in some super class (as long as that pattern was not declared final). Final may not be applied to abstract patterns because their would then be no way to use them or the pattern containing them. A final pattern will prevent objects from implementing the interface of a type since they cannot override that pattern (implementing an interface makes all its members abstract). Final is a statement that an pattern will not be overridden and nothing more.
In addition to preventing a pattern from being overridden the final keyword will also prevent a type from being extended or implemented by any object. Usually only one of the two effects on patterns is relevant, but both are always present.
The 'const
' keyword indicates invariance in value but not reference. Const modifies the type of an entity. The effect is that constant entities are not type equivalent to none constant entities (even when they normally would be). That is, a constant entity may not be assigned to a none constant entity(its constantness could be violated if this were allowed) . On the other hand a none constant value may be assigned to a constant name, indicating that it won't be changed through this reference. When an object is const, its properties are treated as if they were all declared 'const final
'. Final and const may be freely combined.
A entity with a named type can be declared const indicating that the the object referred to by the name may not be modified but the name could be assigned to some other entity. When a const property is assigned some value for which their are no none const references that value is immutable meaning that the object will never be modified from anywhere. There is no explicit indicator that an object is immutable in Opal. Note that patterns are implicitly immutable because they have no value which may be altered. Instead const is used on patterns for other meanings.
Const may be applied to method parameters. When a method declares a parameter to be const it may then be invoked with constant values for that parameter. Methods may be overloaded based on whether or not their parameters are const.
Named entities may be overloaded on whether they are const or not thereby providing a different implementation for an immutable instance of a class verses a mutable instance. Note that to preserve the correct semantics of const the mutable form must implement or extend the const form. When this is done it is not necessary to distinguish between the two forms when instantiating an instance since this will be inferred.
When const is applied to objects of anonymous type, the objects contained in it are treated as const final. This takes effect when the object is completely created, so creation code is free to manipulate these value. In addition all patterns in the object are const. It is an error to declare object members of a const object const or final and it is an error to declare pattern members as const. This is because they are already so.
A pattern that is const may be overridden only by const patterns. On the other hand a none const pattern may be overridden by a const one.
Const has two effects when applied to patterns. First, it indicates that the pattern will not modify its immediate context. More precisely the 'this
' reference in now const. And any object which could be referred to through 'this
', even when not used, is treated as being 'const final
'.
Secondly it indicates that all objects generated by the pattern will be const with all the effects that entails. It is not necessary to declare the special return type self as const when declaring the pattern const. When inheriting if the super type is declared const then the entity does not have to be const. If a super type is declared none const then its sub-types may be const but there super reference will then be const.
Constant objects can't be changed in any way and once an object reference is constant it is impossible to convert back. The keyword mutable may be used to subvert these rules in a controlled way. When a type is declared its properties may be declared mutable. This means that even in constant instances of the class this property will not be const or final, it may be changed by constant methods or any other means. This is useful for things like cached values or other values which do not change the value of the object as a whole. It is up to the programmer to maintain logical constantness. Compilers are free to assume this when optimizing. Alternatively one may like to remove only one of the restrictions while enforcing the other. In this case mutable may be combined with either const or final to indicate that the property has that modifier but the other does not apply (as 'const mutable
' or 'final mutable
').