Task

Demonstrate any means your language has to prevent the modification of values, or to create objects that cannot be modified after they have been created.




import std.random;
 
// enum allows to define manifest (compile-time) constants:
int sqr(int x) { return x ^^ 2; }
enum int x = 5;
enum y = sqr(5); // Forces Compile-Time Function Evaluation (CTFE).
 
// enums are compile-time constants:
enum MyEnum { A, B, C }
 
 
// immutable defines values that can't change:
immutable double pi = 3.1415;
 
 
// A module-level immutable storage class variable that's not
// explicitly initialized can be initialized by its constructor,
// otherwise its value is the default initializer during its life-time.
 
immutable int z;
 
static this() {
    z = uniform(0, 100); // Run-time initialization.
}
 
class Test1 {
    immutable int w;
 
    this() {
        w = uniform(0, 100); // Run-time initialization.
    }
}
 
 
// The items array can't be immutable here.
// "in" is short for "const scope":
void foo(const scope int[] items) {
    // items is constant here.
    // items[0] = 100; // Cannot modify const expression.
}
 
 
struct Test2 {
    int x_; // Mutable.
    @property int x() { return this.x_; }
}
 
// Unlike C++, D const and immutable are transitive.
// And there is also "inout". See D docs.
 
void main() {
    int[] data = [10, 20, 30];
    foo(data);
    data[0] = 100; // But data is mutable here.
 
    // Currently manifest constants like arrays and associative arrays
    // are copied in-place every time they are used:
    enum array = [1, 2, 3];
    foo(array);
 
    auto t = Test2(100);
    auto x2 = t.x; // Reading x is allowed.
    assert(x2 == 100);
 
    // Not allowed, the setter property is missing:
    // t.x = 10; // Error: not a property t.x
}