D const design rationale
Daniel Keep
daniel.keep.lists at gmail.com
Fri Jun 22 20:00:39 PDT 2007
Sean Kelly wrote:
> Daniel Keep wrote:
>> final int x; typeof(x) == int;
>> const int y; typeof(y) == const int;
>> final const int z; typeof(z) == final const int;
>
> Hm. Just to clarify, we both agree that the value of a final integer
> (ie. case 1 above) is effectively constant, correct?
Indeed.
>> "Wait; why is final part of the last type, but not the first?" And what
>> does this mean if you want a class member with final-style binding, but
>> (final const) type semantics?
>>
>> final (final const(int*)) foo;
>>
>> As opposed to
>>
>> final invariant(int*) foo;
>
> Perhaps I'm missing something, but I would rewrite this as:
>
> final const int* foo;
>
> Thus foo cannot be reassigned once set and the data foo refers to may
> not be changed through foo. This is a slightly weaker guarantee than:
>
> final invariant int* foo;
>
> Which says that the data foo refers to is immutable, but I am skeptical
> that this guarantee actually matters much to users.
>
> Or am I completely misunderstanding? And why the parenthesis in the
> second declaration?
(When I wrote the below, I missed precisely what you were saying: the
problem with writing it at "final const int*" is that you've got both
final and const as a storage class; I assumed you were using them as a
type constructor.)
Ok, let's try this instead: in the current system, we have
class Foo
{
final invariant(FunkyType) funky;
this(bool superFunky)
{
if( superFunky )
funky = cast(invariant) new FunkyType;
else
funky = some_global_invariant_funky;
}
}
In this case, we have a final storage (so we can assign the value during
the ctor), and an invariant(FunkyType) value type.
Under your proposal, invariant is replaced with (final const); if we
want the above, it'd become:
final final const(FunkyType) funky;
But how does the compiler tell that second final is storage class or
part of the type constructor? Remember, we could be dealing with a
template that's just shoving "final" out the front of things, so we
can't assume two finals ==> one is a type constructor. So we'd probably
have to do this:
final (final const(FunkyType)) funky;
We can't use *just* "final const FunkyType funky" because then we'd have
an "invariant" storage class: which means the initialiser would have to
be a compile-time constant. Incidentally, the above is also probably
equivalent to:
final(final const(FunkyType)) funky;
Which really doesn't make any sense anyway...
>> I think the thing here is that you're shifting the complexity from
>> invariant into final; instead of invariant meaning two different things
>> with two very different appearances, you've got final meaning two
>> slightly different things with almost identical looks.
>
> I only see final meaning one thing: that the associated value may not be
> reassigned. For concrete types like integers this is effectively the
> same as const, but as Walter said, the integer would be addressable when
> final but not when const. Perhaps this is the source of confusion?
>
> Sean
Yes, but it *also* means "can assign to in a ctor".
Like Lars said, I do think that if there's a way to simplify or
consolidate this, then we should take it. That said, I can see a use
for each of the various cases the new system allows for, and I don't
want to see any of them cut off in the name of "well *I'm* not going to
use it, and I don't like that keyword, so it has to go!"[1]. :)
-- Daniel
[1] I'm not saying that's what you're doing, but I've heard that sort of
argument from a lot of people, so I've become somewhat defensive of the
new stuff: don't take away my new shinies!
More information about the Digitalmars-d
mailing list