Why can't we define re-assignable const reference variable?
Steven Schveighoffer
schveiguy at yahoo.com
Tue Feb 19 07:57:34 PST 2008
"none" wrote
> Why can't we define re-assignable const reference variable?
> i.e. the variable can be re-bind, but it's allowed to change the object it
> points to:
The problem here, none (is that your real name?), is that Walter has tried
several times to achieve exactly that, and each time the syntax that he has
created is either confusing or breaks something else. I think he has given
up, claiming that there is no way to do it, but I think he is wrong in that
respect.
The problem stems from the fact that classes are inherently references and
everything else is not. This in itself is not a problem, and is a
distinction I happen to agree with, but the issue is that there is no easy
way to const-modify the data of a class without also modifying the reference
to the data. In order for this to work, there needs to be a syntax change.
In all the responses to this thread, there is one point of view that I wish
to rebut:
"You can't have mutable references to const classes because any syntax
change you have to make would break generic programming"
Generic programming is already broken. That is, because classes *are*
references and must be created from the heap using the new operator, you
must treat them differently today than other types. For example, if I want
to create a generic type that creates a new version of a type, or uses an
array of the type, depending on whether the type is a class or a struct or
something else, I need to use static if to determine this before creating
the new type.
I believe others have pointed out other examples, but it all comes down to
the fact that yes, classes are inherently different than structs or other
data types, and you have to treat them differently, so saying you cannot
change the language because then you'd have to treat classes differently
than other types is asinine.
I have proposed two syntax changes that I believe would resolve the problem.
One is to allow dereferencing a class type, such as:
const(*C)* c;
Which would translate to *C being the value of type C, and therefore
const(*C)* being exactly what we want. This does not add any keywords, and
also utilizes the * operator in familiar ways, and so it would be in my mind
trivial to introduce and implement in the compiler. The only issue is that
you must restrict the user from declaring a variable or return type of the
dereferenced class type. i.e.:
*C cvalue;
would be illegal.
The only drawback here is that code is going to get really ugly, but I can
live with this because we can make templates that make the code look better.
And in fact, this *fixes* to some degree the difference between classes and
structs for generic programming, because if you want a reference type, you
can do:
valuetype(T)
{
static if(is(T == class))
alias *T valuetype;
else
alias T valuetype;
}
struct hasTailconstRef(T)
{
const(valuetype!(T)) * myref;
}
now, hasTailconstRef.myref is a tailconst reference to a type no matter if
the type is a class, struct, int, or whatever.
The other proposal I have made, which I like better but would be a more
drastic syntax change, is to have a reference operator that "pulls out" the
reference on a class. Other types would be treated like references to the
type:
struct S {}
class C {}
S & s; // equivalent to S * s
C & c; // equivalent to C c
int & i; // equivalent to int * i
With this, you can then use the & operator to declare a tailconst reference
to a class or struct equivalently:
const(C) & c;
const(S) & s;
I have never read any arguments that correctly refute that these options
would work. All I have ever heard is the generic programming argument,
which is totally bogus, and "we've already tried tail-const, it doesn't
work", which isn't an argument at all.
I challenge anyone to tell me why either of these schemes would not work.
-Steve
More information about the Digitalmars-d
mailing list