Immutability First
Immutability refers to data that, after being created or assigned, cannot be changed. That is, the data are read-only and unwritable. Therefore, immutable objects are inherently thread-safe, that is, they can be freely accessed on any thread if no special restrictions exist. In addition, unlike with access to mutable objects, access to immutable objects has no side effects. Therefore, in some scenarios, immutable objects make programs easier to understand and provide higher security.
Immutability applies to both variables and types. Immutable variables are variables whose value cannot be changed after being initialized. Immutable types are types whose underlying data cannot be changed after construction.
In Cangjie, variables defined via let
are immutable variables, and types such as String
and enum
-types are immutable types. These are applications of immutable ideas in Cangjie. The use of immutable variables and types can make programs more secure and facilitate understanding and maintenance of programs.
Function Parameters are Immutable
In Cangjie, formal parameters of all functions are immutable, which means that no values can be assigned to formal parameters. Furthermore, if the formal parameter is of a value type, members of the formal parameter cannot be modified.
struct Point {
var x: Int
var y: Int
init(x: Int, y: Int) { ... }
...
}
func f(a: Point) { // **a** is immutable.
a = Point(0, 0) // Error
a.x = 2 // Error
}
New Variables Introduced by Pattern Matching are Immutable
In Cangjie, variables can be bound during pattern matching, but these bound variables are immutable. Furthermore, if the newly bound variable is of a value type, members of the newly bound variable cannot be modified.
func f(a: ?Point) {
match (a) {
case Some(b) => // **b** is immutable.
b = Point(0, 0) // Error
b.x = 2 // Error
case None => ()
}
}
Closures Capturing Mutable Variables Cannot Escape
In Cangjie, a closure is a self-contained function or lambda. A closure can capture variables from its static scope so that those variables can be accessed even when the function is called from a different scope.
In Cangjie, closures can capture mutable variables, but such closures cannot escape their scope. This restriction avoids unexpected behavior caused by modifications of mutable variables.
func f() {
let a = 1
var b = 2
func g() {
print(a) // ok
print(b) // ok
}
return g // Error. **g** captures mutable variable **b**, so **g** cannot be used as an expression.
}