Const template
Andrei Alexandrescu (See Website For Email)
SeeWebsiteForEmail at erdani.org
Sun Jan 21 19:19:50 PST 2007
Frits van Bommel wrote:
> You didn't respond to my paragraph on classes though:
>
> Frits van Bommel wrote:
> > I also don't see a way this can work for classes (in general). There's
> > no way to limit a non-final method to non-mutating operations that I'm
> > aware of, so it could easily be circumvented by subclassing. Even though
> > that would only allow direct access to non-private fields, mutating base
> > class methods could still be called for the rest (if available). So then
> > the only way to get a const version of a class would be if the class
> > doesn't allow mutations anyway (like java's String). Which leaves us
> > right back where we started :(.
> >
> > And I don't think a 'const' implementation should work for structs and
> > not for classes...
I did when I wrote:
>> That is correct. Interface functions, nonfinal methods, and
>> declared-only functions must be annotated manually.
I meant - yes, you are right.
Today, Walter and myself have come with a semantics for const (as in,
"read-only view" that) seems to be a good starting point. The details
are yet to be ironed out, but here's the basic plot:
* const is a unary type constructor (takes a type, returns a type)
* const is always transitive, meaning that once a value is const, the
entire part of the world accessible through that value is const as well.
This distances D from C++'s shallow view of const (only one level).
* const is not removable legally via a cast. But the compiler must
assume in the general case that a const view may alias with a modifiable
view. This is a weak point of the design. The hope is that in most cases
the compiler will easily prove non-aliasing and can do a good job at
optimizing based on const. Example: all pure functions don't care about
aliasing to start with.
* Shallow const is achievable via final. Final only means a value is not
supposed to be changed, but anything reachable through it can be mutated.
* The syntax for manually-annotated const is:
struct Widget
{
void Foo(const)(int i) { ... }
}
This is in the spirit of current D, because Foo can be seen as a
specialization for a subset of Widget types.
* If you do want to make Foo a template, it's:
struct Widget
{
void Foo(const, T)(T i) { ... }
}
* D avoids the issue of duplicated function bodies in the following way:
struct Widget
{
storageof(this) int* Foo(storageof(this))(int i) { ... }
}
This code transports whatever storage 'this' has to the result type.
More involved type computations are allowed because inside Foo,
typeof(this) includes the storage class. Effectively Foo above is a
template.
* Constructors and destructors can figure the storage class of the
object being constructed. This is useful for selecting different
allocation strategies for immutable vs. mutable objects:
class Widget
{
this(int i) { ... }
this(const)(int i) { ... }
~this() { ... }
~this(const)() { ... }
}
Const cdtors can obviously mutate the object being cdted. In a cdtor,
'const' is not enforced -- it's just an information for the programmer.
* Walter sustains that given the above, there will never be a need to
overload member functions based on const. I disagree, but I couldn't
come up with a salient example. Besides, I don't care that much because
the semantics above do allow telling const from nonconst, just in a
roundabout way.
Andrei
More information about the Digitalmars-d
mailing list