Community

Walter Bright wrote:
> http://www.digitalmars.com/d/const.html
So in short, 'const' protects data and 'final' freezes references. How
do these two apply to an int declaration?
const final int x = 5;
Is either a compiler error? are they synonyms in this case?
This aspect of the design seems very straightforward, aside from the
question above. What bothers me, however, is the use of 'invariant'.
Adding a third keyword simply to represent data that's "really really
const" just confuses things to me, and I haven't been able to get past
this. Given that adding a third keyword doubles the number of
permutations for describing const behavior, I think the addition of
'invariant' should be very carefully considered. Is there any way we
could get along without it? I realize that 'invariant' would be rarely
used in practice, but that doesn't change the impact an additional
attribute has on the complexity of this design.
Frankly, I think we could almost get away with one keyword, but for the
fact that D doesn't use a reference qualifier for class references.
About the only workaround I could think of to describe a const reference
to mutable data would be something like this:
const (ref MyClass) x;
And inserting the 'ref' seems even more confusing than simply having
'final' as in the current design.
Sean

Sean Kelly wrote:
> Walter Bright wrote:
>> http://www.digitalmars.com/d/const.html
>
> So in short, 'const' protects data and 'final' freezes references. How
> do these two apply to an int declaration?
>
> const final int x = 5;
>
> Is either a compiler error? are they synonyms in this case?
It's not an error, it's just redundant.
> This aspect of the design seems very straightforward, aside from the
> question above. What bothers me, however, is the use of 'invariant'.
> Adding a third keyword simply to represent data that's "really really
> const" just confuses things to me, and I haven't been able to get past
> this.
invariant = the data doesn't change
const = the data cannot be changed through this reference to it
> Given that adding a third keyword doubles the number of
> permutations for describing const behavior, I think the addition of
> 'invariant' should be very carefully considered. Is there any way we
> could get along without it? I realize that 'invariant' would be rarely
> used in practice, but that doesn't change the impact an additional
> attribute has on the complexity of this design.
In C++, sometimes const means invariant, and sometimes it means readonly
view. I've found even C++ experts who don't know how it works.
> Frankly, I think we could almost get away with one keyword, but for the
> fact that D doesn't use a reference qualifier for class references.
> About the only workaround I could think of to describe a const reference
> to mutable data would be something like this:
>
> const (ref MyClass) x;
>
> And inserting the 'ref' seems even more confusing than simply having
> 'final' as in the current design.
C++ tries too hard to use one keyword to do it all. The result is, as
the article showed, serious difficulties.

Walter Bright wrote:
> http://www.digitalmars.com/d/const.html
It's a good article. However, it could really use some examples. The article on
scope was very convincing because it gives plausible use-cases. In particular, I
think there needs to be an example for 'invariant'. When is 'const' not good enough?
Where you state that invariant solves the aliasing problem, you could prove it
by rewriting the example from the C++ section.
QUOTE ---
But there is a need for a constant declaration referencing a mutable type.This
is provided with the final storage class for declarations...Its main purpose is
...[that it]...can be mentally separated from variable declarations that are
meant to change
---
I don't find this very convincing. Is the mental benefit really significant
enough to justify the extra complexity? The existence of three const-related
keywords is pretty tough on mental space!
QUOTE ----
int x = 3;
const int *p = &x;
*p = 4; // error, read-only view
x = 5; // ok
int y = *p; // y is set to 5
This is one instance of the so-called aliasing problem, since while the above
snippet is trivial, the existence of such aliases can be very hard to detect in
a complex program. It is impossible for the compiler to reliably detect it. This
means that the compiler cannot cache 4 in a register and reuse the cached value
to replace *p, it must go back and actually dereference p again.
---
Shouldn't that be: "the compiler cannot cache 3 in a register" ?

After reading the articles by Walter referred to recently, I'm less confused
that I was, but would still appreciate some further explanation.
So should "const foo bar = baz" be an error if foo is a value type, on the
basis that one should be using "invariant" or maybe final? It it safe to
have two things const/invariant that become identical depending on type?
And does "final" exist *solely* so that you can approximate "invariant" for
objects as well as for structs and scalars? I can see its use when you want
something to be invariant but with the stipulation that it must exist in
memory and have an address. In which case, why have final vs invariant at
all, rather than having final be, for example, "weak invariant" or "stored
invariant" or something like that? From here, final just looks
*semantically* like "a poor man's invariant".

Don Clugston wrote:
> QUOTE ----
> int x = 3;
> const int *p = &x;
> *p = 4; // error, read-only view
> x = 5; // ok
> int y = *p; // y is set to 5
>
> This is one instance of the so-called aliasing problem, since while the
> above snippet is trivial, the existence of such aliases can be very hard
> to detect in a complex program. It is impossible for the compiler to
> reliably detect it. This means that the compiler cannot cache 4 in a
> register and reuse the cached value to replace *p, it must go back and
> actually dereference p again.
> ---
> Shouldn't that be: "the compiler cannot cache 3 in a register" ?
No. At "*p = 4;" the compiler can't cache 4, because then at "int y = *p;" y
would become 4 instead of 5.
Although in the example it's moot because "*p = 4;" is an error.
--
Remove ".doesnotlike.spam" from the mail address.

Leandro Lucarella wrote:
> Walter Bright, el 22 de junio a las 01:07 me escribiste:
>> Sean Kelly wrote:
>>> Walter Bright wrote:
>>>> http://www.digitalmars.com/d/const.html
>>> So in short, 'const' protects data and 'final' freezes references. How do these two apply to an int declaration?
>>> const final int x = 5;
>>> Is either a compiler error? are they synonyms in this case?
>> It's not an error, it's just redundant.
>
> Shouldn't be better to be an error? So it's more clear that final makes
> sense only for reference types.
Allowing it allows cleaner generic code, otherwise templates would often
have to check whether parameters were value or reference types.

Frits van Bommel wrote:
> Leandro Lucarella wrote:
>> Walter Bright, el 22 de junio a las 01:07 me escribiste:
>>> Sean Kelly wrote:
>>>> Walter Bright wrote:
>>>>> http://www.digitalmars.com/d/const.html
>>>> So in short, 'const' protects data and 'final' freezes references.
>>>> How do these two apply to an int declaration?
>>>> const final int x = 5;
>>>> Is either a compiler error? are they synonyms in this case?
>>> It's not an error, it's just redundant.
>>
>> Shouldn't be better to be an error? So it's more clear that final makes
>> sense only for reference types.
>
> Allowing it allows cleaner generic code, otherwise templates would often
> have to check whether parameters were value or reference types.
Indeed; we already need to special-case functions that return void. "It
can't be *that* bad!" In some cases, it means an entire template has to
be duplicated *just* for the void case. I had to do this for a
coroutine implementation, and was not happy about it.
-- Daniel

Walter Bright wrote:
> Sean Kelly wrote:
>> Walter Bright wrote:
>>> http://www.digitalmars.com/d/const.html
>>
>> So in short, 'const' protects data and 'final' freezes references.
>> How do these two apply to an int declaration?
>>
>> const final int x = 5;
>>
>> Is either a compiler error? are they synonyms in this case?
>
> It's not an error, it's just redundant.
Okay, thanks.
>> This aspect of the design seems very straightforward, aside from the
>> question above. What bothers me, however, is the use of 'invariant'.
>> Adding a third keyword simply to represent data that's "really really
>> const" just confuses things to me, and I haven't been able to get past
>> this.
>
> invariant = the data doesn't change
> const = the data cannot be changed through this reference to it
And a 'const' at the declaration point implicitly means 'invariant'.
>> Given that adding a third keyword doubles the number of permutations
>> for describing const behavior, I think the addition of 'invariant'
>> should be very carefully considered. Is there any way we could get
>> along without it? I realize that 'invariant' would be rarely used in
>> practice, but that doesn't change the impact an additional attribute
>> has on the complexity of this design.
>
> In C++, sometimes const means invariant, and sometimes it means readonly
> view. I've found even C++ experts who don't know how it works.
Odd. The C++ system always seemed extremely simple to me.
>> Frankly, I think we could almost get away with one keyword, but for
>> the fact that D doesn't use a reference qualifier for class
>> references. About the only workaround I could think of to describe a
>> const reference to mutable data would be something like this:
>>
>> const (ref MyClass) x;
>>
>> And inserting the 'ref' seems even more confusing than simply having
>> 'final' as in the current design.
>
> C++ tries too hard to use one keyword to do it all. The result is, as
> the article showed, serious difficulties.
I personally find the use of three keywords to represent three
overlapping facets of const behavior to be very confusing, and am
concerned about trying to explain it to novice programmers. With three
keywords, there are six possible combinations:
final
const invariant
final const
final invariant
const invariant
final const invariant
That some of these may be redundant just serves to further confuse the
issue in my opinion. So I wondered whether one of the keywords could be
done away with. Previously, you said 'invariant' may only apply to data
whose value can be determined at compile-time, thus I imagine it can
only apply to concrete/data types (ie. not classes). Assuming this is
true, I wonder whether there is truly a point in having 'invariant' at
all. Assuming it were done away with, the system becomes much simpler
to me:
final
const
final const
And that's it. 'final' means a reference cannot be rebound, 'const'
means the data cannot be altered (through the reference), and 'final
const' means that both the reference is frozen and the data cannot be
changed. And that's it. That the existence of invariant required the
addition of parenthesis on class invariants just serves to strengthen
the argument in my mind. So in short, I'm just not convinced that
'invariant' provides enough utility to warrant the cost in complexity
and broken consistency (unittest doesn't require parens, so why does
invariant?).
Sean