www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - =?utf-8?B?4oCYZmluYWzigJkgdmFyaWFibGVzOiBhbiBhbHRlcm5hdGl2ZSBkZWZpbmk=?=

I propose to enhance the concept of ‘final’ to variables in order fill a  
much needed place in the current type system. Final variables would be  
transitive (a.k.a. deep), a super-type of non-final, assignable only at  
declaration and apply only to references. Essentially, it would be a  
references only version of ‘const’. Despite this similarity, it is  
orthogonal to both the immutable-mutable-const and the shared-local-scope  
(a.k.a. shared-heap-stack) type trees. The primary reasons for proposing  
yet another type qualifier is bug 2095 and the lack of an equivalent of  
‘const’ for the shared-local-scope storage type system.

Regarding Bug 2095
Bug 2095 occurs because a reference to a reference type is implicitly  
convertible to a reference to a reference super-type. i.e.

class A {}
class B : A {}
B[] b = new B[10];
A[] a = b;         // Practically, this is really important
a[0] = new A();    // But allowing this causes bugs, since b has also  
changed

Now, the implicit conversion of B[] to A[] is really important for subtype  
and all functions operating on arrays of the super-type in order to avoid  
casting left, right and center. However, if the implicitly converted  
super-type array is assigned to, and then the original array is accessed,  
random code execution can occur. Similarly, immutability can be  
circumvented.

Final solves this problem by providing an alternative implicit conversion  
of B[] to final A[]. E.g.

final A[] fa = b; // Still valid, and mutability/storage isn’t changed.
a[0] = new A();   // But now this is a compile time error.

Regarding shared-local-scope
The storage type system, consisting of shared, local and scope provides  
many correctness and performance advantages. However, akin to mutable and  
immutable there is no safe way to cast between them. This is an undesired  
situation as it would require three separate variants of most functions.  
The currently allowed implicit conversion between local and scope has  
resulted in functions being prevented from returning explicit scope types.  
However, a scope object can still escape, resulting in bugs.

Final references can not escape a scope as they can only be assigned at  
declaration. Thus, final scope and final local may be implicitly casted  
between themselves and either may be implicitly casted to final shared.  
(The reason final shared may not be implicitly casted to final local or  
final scope is that member variables will be protected by memory fences  
and thus are accessed differently at the machine level)

Regarding Transitivity
Though bug 2095 would require arrays of array, etc to be implicitly  
converted to final in a transitive manner, complete transitivity is not  
required and represents a limitation on the actual objects. It is the need  
to guarantee that final variables can not result in an object escaping its  
scope that motivates full transitivity. In a situation where the storage  
type of member variables and member returns is dictated by an object’s own  
storage type, the implicit casting of final-storage-types results in the  
member variable and return storage types to become unknown, necessitating  
the implicit casting of them to final and thus transitivity.

Additional ‘final’ restrictions
Functions whose return type is final may result an object’s escape. This  
can occur only when the returned object is final or scope. While returning  
scope types is already illegal, but returning a final object may be needed  
and logically valid. However, as a potentially dangerous operation  
explicit casting should be required for final types. Another possible  
escape could occur when final member variables are assigned during  
construction and explicit casts should again be required.
Mar 21 2009