const

Oskar Linde oskar.lindeREM at OVEgmail.com
Fri Mar 28 06:21:13 PDT 2008


Walter Bright wrote:
> I appreciate the time and effort you made to explain your thoughts. I'll 
> try and answer them.

Thank you for your explanation. It must be quite an effort battling all 
the negativism against it. I'll try to make this a constructive post.

> Benji Smith wrote:
>> CONST

[snip]

> I understand your and others' frustration with const, and here's what I 
> think it is based on:
> 
> 1) We worked hard on what is the right way to do const for a year. This 
> included at least 3 very different implementations of const that were 
> released. The first two turned out to be very wrong and unworkable, and 
> we learned from that how to do it right. 

Ironically, I found the first implementation of const to be the best of 
the three. There were issues, but the design was for the most part 
sound. My main complaint was the bad choice of keywords. (My personal 
theory is that the poor choice of keywords indirectly influenced the 
design in negative ways. In particular the misconception that const had 
anything to do with constants.) I will not muddle the issues by arguing 
keyword names in this post though.

I think the current const regime suffers from a greater degree of 
keyword overloading and redundancy than the original one did.

I will try to communicate an idea for what I would believe would make 
significant simplifications without the loss of any expressive power. 
(this is mostly from a post I wrote, but never submitted a about two 
months ago.)

I will start with what I call "plain data types", i.e:

* all primitive non-reference types (int,float,char,...)
* structs and unions containing only plain data types.

Plain data types are represented by binary data patterns stored in 
registers, on the stack, on the heap or just by the compiler during 
compilation. The data is not interpreted by the compiler as a reference 
to other data in any way (even though it could, like in the case of an 
array index), so there is no notion of transitivity here.

When it comes to data referred to by a symbol (like a variable name) 
there are only two cases: variable and constant data. D1.0 handles this 
quite well with the concept of "storage const". Variables with a const 
storage can not be changed, but that fact is not reflected in the type 
of the data. Does the constancy have to be a part of the type? I used to 
believe so, but have been unable to find a good reason. Binding 
constancy is a local thing. Example or how it could work:

int a;
"constant" int b;

typeof(a) == int
typeof(b) == int
typeof(&a) == int*
typeof(&b) == invariant(int)*

This leads to my first observation:

1. Plain data types don't need the storage constancy to be a part of the 
type.

(I can elaborate on this further if anyone is interested.)

My second observation is regarding the so called "manifest constants". 
Walter stating that there needs to be a way to declare constants that 
aren't "const" or "invariant" actually reinforces my belief that my 
first observation is correct. The only reason I have found for the 
manifest constants are that they don't occupy storage in the object 
file. I have asked before but never gotten an answer: Can't this be 
solved automatically by the compiler instead?

I will assume that it could, so:

2. Every constant could be a "manifest" constant and just like a 
template not be instantiated unless it has its address taken.

This would, as a side effect, make the entire enum keyword debacle void, 
as the need for a separate keyword vanishes.


Now, what about the concepts of const/invariant? They have nothing to do 
with the actual data, and only make sense in relation to a reference to 
such data. Consider:

invariant(int)* a;

Here, a is actually not a pointer to an invariant int. It is a pointer
that assumes the int it points to is "invariant". The difference is
subtle but quite important. Likewise:

const(int)* b;

is not a pointer to a const int. It is a pointer through which the user 
is disallowed to change the int. That doesn't mean that the int it
points to is actually const.

the const(...)* and invariant(...)* part of the type declaration should 
actually be considered a part of the pointer type. Not a part of the 
target type.

So, const and invariant are type meta qualifiers, that carry assumptions 
about the data. Those assumptions make sense in the context of 
references, but not in declarations of plain data variables. For 
example, given:

const int x = 5;

D 2.010 assigns the type of &x const(int)*. But I would consider that 
wrong. The type should be invariant(int)*, since x is storage constant. 
The actual type of x could actually just as well be int (observation 1). 
Local (storage) constancy doesn't need to be a part of the type.

Now, I will not discuss the keywords used for reference constancy, but I 
think the keyword used to declare constants should be "const". Apart 
from being how it already almost works in D2, it would have the major 
advantage of making:

const x = 5;

mean exactly the same thing in D1 and D2!

So, without any loss of power, transitivity or anything else, one can 
simplify the language and make the constancy of plain data compatible 
between D2 and D1.

That is what I believe at least.

-- 
Oskar



More information about the Digitalmars-d mailing list