Const sucks
Regan Heath
regan at netmail.co.nz
Tue Sep 11 02:42:24 PDT 2007
Daniel Keep wrote:
> This problem seems to be unique to structs and classes. This is because
> every other reference type is written in such a way that you can "split"
> the type in such a way as to get tail-const semantics. For example:
> const(char[]) versus const(char)[]. This can't be done with structs or
> classes since their types are single identifiers.
I came to the same conclusion, the basic problem is the inability to put
a * or [] outside the () of const.
> So what we need is some way to write that split. Really, what we're
> saying is "I don't want *this* to be const, but I do want what it
> references to be const".
Exactly.
> So, stealing a little bit of C++ syntax, what about "const& T" being a
> tail-const version of some struct or class T? Since this could
> potentially introduce synonyms in other places, I would also propose the
> following:
>
> const& int a; // Error: cannot use reference const on an atomic type
> const& int* b; // Error: equivalent to const(int)*
> struct V { int a; }
> const& V c; // Warning: V does not have any references
> struct R { int* a; }
> const& R d; // OK
> class C {}
> const& C e; // OK
>
> Yes, this means there is a distinction between structs, classes and
> "everything else". But honestly, I don't think we can have tail const
> without this distinction. Maybe disallowing const& on arrays and
> pointers isn't a good idea; but I do think we need some kind of
> tail-const for structs and classes.
>
> Thoughts?
In D when we write:
Foo f;
we are declaring a reference to a Foo. The problem, as you mentioned is
the inability to seperate the reference from the Foo for purposes of
declaring const, so...
I was initially thinking that for classes we might write:
class Foo { int a; }
const(Foo)& pFoo; //pFoo can change, pFoo.a cannot
Where the & doesn't introduce another reference or level of indirection,
in fact it does _nothing_ at all except allowing us to place it outside
the () of const.
Meaning, that these two declarations would in fact be identical:
Foo& pFoo;
Foo pFoo;
which will no doubt bother some people, perhaps a lot of people?
The first form could be made illegal, after all it's pointless(right?)
to take a reference to a reference.
Alternately, and I think I might prefer this solution, perhaps _adding_
something to the const() is the solution. eg.
class Foo { int a; }
const(*Foo) pFoo; //pFoo can change, pFoo.a cannot
As in, were saying "the value of Foo is const", therefore implying the
reference is not.
As for structs, as someone else has mentioned there isn't really any
difference between making a struct variable const and making all members
of that struct const, without a pointer or reference they are the same
thing. So, saying:
struct Bar { int a; Foo pFoo; }
const(Bar) bar;
Is perfectly sufficient in that case.
The difference occurs when you want to make _some_ of the members consts
and not the others, typically you want to make references/pointers
const, or tail const.
The syntax:
struct Bar { int a; Foo pFoo; }
const(Bar)& bar;
doesn't make the same sense for structs because there is no reference
involved (as many programmers would expect upon reading that).
Neither does the * syntax I proposed above:
struct Bar { int a; Foo pFoo; }
const(*Bar) bar;
because that would logically make all members of the struct const, and
we get that already.
Assuming there is even a requirement to make select members of a struct
(initially declared without const) const (if there isn't we have no
problem) then using a template seems the most sensible solution. It
would also allow you to apply const or tail const where appropriate. eg.
From this initial struct:
struct Bar {
int a; //we want this to be const
Foo pFoo; //we want this to be tail const
}
Our template generates this:
struct BarConst
{
const int a;
const(*Foo) pFoo;
}
Regan
More information about the Digitalmars-d
mailing list