There seems to be some confusion (both from the original question and due to the large commentary) regarding immutability, I thought I'd add aside.
When you say immutable int i = 42
, you say that I will not be changed, and not that this value is known at compile time. immutable
is actually a type modifier and creates a new type. immutable T
is a short hand for immutable(T)
. immutable(T)
creates a T that can never be changed, that is, if you read the value and then call the function, the value will be the same. Compare this to const(T)
, which provides a weaker guarantee that this type instance will not be changed, but someone may have changed access to it somewhere else, so if you read the value and then call the function, you donโt can accept the value will be the same.
In general, immutable(T) != T
However, there are certain situations when they are implicitly converted into each other. If T is a type that is said to have no "volatile indirection", for example. That is, if I pass the function a immutable(int)
, they will receive a copy - there is no way that this function can change the value passed by me, because it is copied - if the type system did not allow this, it would just be annoying without any additional guarantees , therefore, the D-type system allows this. However, if I pass in immutable (int *), which can be changed by the calling function. In the case of structures, if any member has a variable indirectness, then, as they say, it also has.
So, in order to turn away from theory and return to more practical issues, it is not entirely true that immutable values โโmust be known at compile time and that there is no good way to create them. However, a single mutation can occur inside the constructor. For simple scalar types, this is pretty obvious:
immutable(int) i = rand();
But what about something like an object? Well, to build type T we use
auto t = new T();
therefore, to construct the type of immutable (T), we use
auto t = new immutable(T)();
here is a more complete small example
class Useless { int i; this(int i) { this.i = i; } } int main(string[] args) { auto o = new immutable(Useless)(cast(int) args.length);
As you can see, mutation can occur inside the constructor. You can read member variables, but you cannot write them (immutability is transitive, that is, each member (and each member of the members) becomes immutable if the parent does. You can call methods only if they are marked as const
.
I apologize for the impassivity, but I see that many people seem to be confused on this issue.