Extended Type Design.

Andrei Alexandrescu (See Website For Email) SeeWebsiteForEmail at erdani.org
Mon Mar 19 22:34:13 PDT 2007


Tyler Knott wrote:
> I think I've got this.  Is the following right?
> 
> *final variables can be assigned only once in their lifetime, but are 
> otherwise normal variables (i.e. they *do* have a memory address), 
> except where constant folded by the compiler (this should be completely 
> transparent to the programmer).

Correct.

> *const and invariant only make sense when applied to references, 
> otherwise they are ignored or (preferably) errors.

Correct.

> *const references cannot be used to mutate the data they reference, but 
> the data they reference may be mutated directly or through other 
> non-const, non-invariant references.

Correct.

> *invariant references only reference data that will never be mutated 
> (e.g. final variables).

Ambiguously expressed. But I think I see what you mean, e.g. you can 
take the address of a final int and bind it to an invariant int*, like so:

final int x = 42;
immutable int* p = &x; // correct

> *Both const and invariant references can be reassigned unless they are 
> also final references.

Correct.

> *Conversely, when final is applied to the declaration of a reference, 
> only that reference is protected from mutation, not the data it 
> references, unless that reference is also const or invariant.

Correct.

> *Neither const nor invariant references can be cast to non-const or 
> non-invariant references directly.

Correct.

> *The address of any variable or the value of any reference (of 
> compatible type) can be assigned to const references.

Correct. (Just like in C++.)

> *Only the addresses of final variables (I'm sure of this), the direct 
> result of "new" statements (not sure on this one), and the values of 
> other invariant references may be assigned to invariant references.

Yes, yes (and more), and yes.

New statements can be solved easily by just requiring people to qualify 
the type created:

invariant int* p = new invariant int(42);

User-defined types will have a chance to define constructors for 
invariant objects. Those constructors will have the chance of modifying 
the object being constructed, but won't be able to alias 'this' and 
member addresses to modifiable pointers.

The deeper problem is with functions that return pointers that could be 
assigned to either mutable or invariant symbols. For example, array.dup. 
Take a look:

int[] array = [1, 2, 3];
invariant int[] brray = array.dup; // should work
invariant int[] crray = array.dup; // should work, too!

I am working on a solution for this issue. The problem is rather 
general. Consider a function char[] readln() that reads a line from the 
standard input, creating a fresh string each call. That string should be 
assigned to char[] or invariant char[].

> *const and invariant are viral (i.e. all references in the data 
> referenced by a const or invariant reference is also const or invariant, 
> respectively, when access through the const or invariant reference).

"Transitive." Yes.

> *final, when applied directly to POD structures (structs and array 
> references), means no members of that structure can be modified after 
> assignment, but is non-viral to references within the POD structure. 
> (Not sure on this.)

Correct. "final x" freezes all of x's bits.

> *Function declarations cannot overloaded based on const or invariant. 
> (Pretty sure on this.)

Walter is mildly unconvinced about such overloads' utility, I think they 
should be allowed without being required.

I'll snip your examples, which are correct and also raise a couple of 
interesting questions that are being worked on.


Andrei



More information about the Digitalmars-d mailing list