const correctness ----------------- TODO: const/exclusive/readonly/restrict/volatile has been replaced: const --> var (default is const) exclusive --> shared (default is exclusive) restrict/readonly/volatile has been removed. Use combinations of shared/var instead. ------ A variable of a type qualified with "const" may not be modified. For example: const int a = 4; a = 3; // Not allowed! This is how to apply it to an array: const int[3] = [ 1, 2, 3 ]; It can also be placed on pointers, or values that pointers point to: int a = 1; int b = 2; // The variable that p points to may not be changed const int p^ = a; p^ = 10; // Not allowed! p = @b; // Ok // q may not be changed to point to something else int q const^ = a; q^ = 10; // Ok q = @b; // Not allowed! Const applies to entire structs, and by default also data that pointers in the structs point to: const (int x; int y) point = [3, 6]; const ((int x; int y) from; (int x; int y) to) line = [[3,6], [1,2]]; point.y = 5; // Not allowed! line.from.x = 7; // Not allowed! int a = 1; const (int x; int^ p) something = [3, @a]; something.a = 3; // Not allowed! something.p = @point.x; // Not allowed! something.p^ = 2; // Not allowed! "transitive" const ------------------ The const keyword optionally takes a parameter, which means that the const qualifier is active only if the variable specified in the parameter has an active const qualifier. It can be used with functions: const[s] zstring own[s]^ strstr(const zstring^ haystack; const zstring^ needle); int main() { zstring own^ hw = "Hello World"; const zstring own^ dm = "Don't Modify"; zstring^ a = strstr(hw, "World"); const zstring^ b = strstr(dm, "Modify"); zstring^ c = strstr(dm, "Modify"); // Not allowed! return 0; } And structs: typedef Tree = ( const[this] Tree own^? left, right; int value; ); () main() { Tree a = [none, none, 23]; const Tree root = [@a, none, 0]; a.value = 1; // Ok root.left?^.value = 1; // Not allowed! (left has transitive const) } readonly vs immutable vs exclusive ---------------------------------- Read only: May not be modified by "us", but could be modified from somewhere else. Immutable: It can be assumed that this variable is not modified. Exclusive: May only be modified by "us". conversion to immutable ----------------------- const int^ a = b; // when is this allowed? When may "pointer-to-immutable" types accept non-immutable pointers? In any of these cases: * If we have an const or exclusive pointer which is known to point to the address (including any pointer we assign from). Then nobody else can have write access. * If we own the address, and we don't access the address as a writable object (through any pointer) after the assignment. The fact that the object is owned by us means that we know the presence of other pointers to it. conversion to exclusive ----------------------- Same rules as for conversion to immutable, except that it's not allowed to have immutable pointers to the address. exclusive access could be used in threaded applications: // Queue owns and has exclusive access to objects while they are in the // queue. Then it transfers them to anyone who calls dequeue. () enqueue[T](ParallelQueue[T]^ queue, exclusive A^ own obj); exclusive A^ own dequeue[T](ParallelQueue[T]^ queue); // Takes an object (and gets exclusive access and ownership) and calls a // callback with it as the parameter when an event occurs. () registerEvent(exclusive A own^ obj, ()(exclusive A^ obj) callback); defaults -------- * const, readonly or mutable? * transient or not transient? I think the default for variables in structs should be "transitive const", i.e. const[this], unless const or readonly is specified. Pointer destinations should similarly default to const[pointer]. const should imply readonly, and a "const" value should be type-compatible with a "readonly" variable. const seems more useful than readonly, because most code is not going to work if the data it uses is being changed. But readonly can be useful if you store a pointer to something which might be changed, and in parallel code. On the other hand, for most use cases it's probably easier for the (novice) programmer to only have readonly and not have to think about mutability. Except in some cases, such as parallel programs.