People often express frustration with const and immutable
in D 2.0 and wonder if it is worth it.

It makes function interfaces more self-documenting. Without
transitive const, for all pointer/reference parameters one must rely on
the documentation (which is always missing, out of date, or wrong). Note
that without transitivity, C++ const is nearly useless for such
self-documentation, which is why C++ programmers tend to rely on
convention instead.

It makes for interfaces that can be relied upon, which becomes
increasingly important the more people that are involved with the code.
In other words, it scales very well. People who are involved with
projects with large teams of programmers say that lack of const
makes their lives difficult because they cannot rely on the compiler to
enforce convention. The larger the team, the worse it gets. Managing
APIs is critical to a large project - it's why BASIC doesn't scale (for
an extreme example).

Const transitivity makes for some interesting optimization
opportunities. The value of this has not been explored or exploited.

Here's the biggie. Points 1..3 are insignificant in comparison. The
future of programming will be multicore, multithreaded. Languages that
make it easy to program them will supplant languages that don't.
Transitive const is key to bringing D into this paradigm. The surge in
use of Haskell and Erlang is evidence of this coming trend (the killer
feature of those languages is they make it easy to do multiprogramming).
C++ cannot be retrofitted to supporting multiprogramming in a manner
that makes it accessible. D isn't there yet, but it will be, and
transitive const will be absolutely fundamental to making it work.

Of course, for writing single-threaded one man programs of
fairly modest size, const is not particularly useful.
And in D const can be effectively ignored by just not using it, or
by using D 1.0. The only place const is imposed is with the immutable
string type.

Tail const is the complement of head const - everything reachable
from the const type is also const except for the top level. For
example:

tailconst(int**) p;

would be read as p being a: mutable pointer to const pointer
to const int. Head const combined with tail const yields transitive
const.
D doesn't have tailconst (the keyword is there just for
illustrative purposes) as a distinct type constructor.

The example evaluates f.len only if it is needed.
Foo is logically const, because to the observer of the object
its return values never change after construction.
The mutable qualifier says that even if an instance
of Foo is const, those fields can still change.
While C++ supports the notion of logical const, D does not,
and D does not have a mutable qualifier.

The problem with logical const is that const is no longer
transitive. Not being transitive means there is the potential
for threading race conditions, and there is no way to determine
if an opaque const type has mutable members or not.

Readonly has a well established meaning in software to
mean ROM, or Read Only Memory that can never be changed.
For computers with hardware protection for memory pages, readonly
also means that the memory contents cannot be altered.
Using readonly in D to mean a read only view of memory that could
be altered by another alias or thread runs counter to this.

Since most (nearly all?) function parameters will not be modified,
it would seem to make sense to make them all const by default,
and one would have to specifically mark as mutable those that would
be changed. The problems with this are:

It would be a huge break from past D practice, and practice
in C, C++, Java, C#, etc.

It would require a new keyword, say mutable.

And worst, it would make declarations inconsistent:

void foo(int* p) {
int* q;
...
}

p points to const, and q points to mutable.
This kind of inconsistency leads to all sorts of mistakes.
It also makes it very hard to write generic code that deals with
types.

A static class member is part of the global state of a program,
not part of the state of an object. Thus, a class having a mutable
static member does not violate the transitive constness of an object
of that class.