www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The "const"-war: resolution in the other direction?

reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Hi there,

no, I do not plan to reopen the good old "const" war once again by defending
the C++ position or trying to smuggle some of it into D. Just the contrary:
maybe, it can be solved by going one step further:

Looking at the spec:
"The const attribute declares constants that can be evaluated at compile
time."

Why then should we speak of "storage" of constants at all? Primarily, a
const is not "stored" at all. It is instead handled at compile time and can
therefore be seen just like a literal. There is no way to take an address
of a literal, therefore it should not be possible to take an address of a
const either.

#############################
For primary type this already is, what happens:

------------------
const int x = 7;
int* y = &x;
------------------

will give you a compiler error "'7' is not an lvalue".
#############
For structs, the "const" seems to be ignored completely:

----------------
struct s {
    int x;
}

const s y = { x:7 };

int
main() {
    s* z = &y;
    z.x = 13;
    printf("%i\n",(*z).x);
    return 0;
}
----------------

will simply print "13"
#############
For strings:

----------------
const char[] str = "hallo";

int
main() {
    str[1] = 'e';
    printf(str);
    return 0;
}
----------------

gives a segfault at the assignment, probably because the data is stored in a
readonly data segment.
##############################################

This clearly is a mess. My suggestion would be to handle const structs and
const arrays just like literals. Taking the address is not possible,
instead, you would first have to copy the content to a local variable (just
like for a literal). Passing const values as inout/out parameters is not
possible.

For in parameters, it would first have to be cleared up whether "in" means
call-by-value or call-by-reference. In the first case, there is no problem.
In the second case, the compiler should make sure, that the argument really
is not written to. Effectively, this would mean, that "in" arguments can
only be handled like constants: assignment is not possible, taking the
address is not possible, and they can only be used as "in" parameters.

Unlike C/C++, where arguments automatically turn into local variables, this
would not be the case for "in" arguments.

Ciao,
Nobbi
May 26 2004
parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
Part of the problem here is that 'const' is overloaded:

1) a compile-time constant, such as your example below

2) a function/method argument that disallows write-access as part of DbC

3) read-only data, which can be placed in an alternate physical medium such
as ROM

The first two get all the attention, but I'd like to remind folks about the
value of #3 ... arguably the dominant factor when it comes to the world's
most prevalent CPU: the humble microcontroller. This is why 'const' is oft
discussed in terms of "storage class".

I'm tempted to argue that only #3 has the right to be called 'const', since
#1 is handled by folding, or enum, or whatever, and #2 should be handled by
the 'in' keyword ...

- Kris


"Norbert Nemec" <Norbert.Nemec gmx.de> wrote in message
news:c91fvi$ru8$1 digitaldaemon.com...
 Hi there,

 no, I do not plan to reopen the good old "const" war once again by

 the C++ position or trying to smuggle some of it into D. Just the

 maybe, it can be solved by going one step further:

 Looking at the spec:
 "The const attribute declares constants that can be evaluated at compile
 time."

 Why then should we speak of "storage" of constants at all? Primarily, a
 const is not "stored" at all. It is instead handled at compile time and

 therefore be seen just like a literal. There is no way to take an address
 of a literal, therefore it should not be possible to take an address of a
 const either.

 #############################
 For primary type this already is, what happens:

 ------------------
 const int x = 7;
 int* y = &x;
 ------------------

 will give you a compiler error "'7' is not an lvalue".
 #############
 For structs, the "const" seems to be ignored completely:

 ----------------
 struct s {
     int x;
 }

 const s y = { x:7 };

 int
 main() {
     s* z = &y;
     z.x = 13;
     printf("%i\n",(*z).x);
     return 0;
 }
 ----------------

 will simply print "13"
 #############
 For strings:

 ----------------
 const char[] str = "hallo";

 int
 main() {
     str[1] = 'e';
     printf(str);
     return 0;
 }
 ----------------

 gives a segfault at the assignment, probably because the data is stored in

 readonly data segment.
 ##############################################

 This clearly is a mess. My suggestion would be to handle const structs and
 const arrays just like literals. Taking the address is not possible,
 instead, you would first have to copy the content to a local variable

 like for a literal). Passing const values as inout/out parameters is not
 possible.

 For in parameters, it would first have to be cleared up whether "in" means
 call-by-value or call-by-reference. In the first case, there is no

 In the second case, the compiler should make sure, that the argument

 is not written to. Effectively, this would mean, that "in" arguments can
 only be handled like constants: assignment is not possible, taking the
 address is not possible, and they can only be used as "in" parameters.

 Unlike C/C++, where arguments automatically turn into local variables,

 would not be the case for "in" arguments.

 Ciao,
 Nobbi

May 26 2004
parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Kris wrote:

 Part of the problem here is that 'const' is overloaded:
 
 1) a compile-time constant, such as your example below
 
 2) a function/method argument that disallows write-access as part of DbC
 
 3) read-only data, which can be placed in an alternate physical medium
 such as ROM
 
 The first two get all the attention, but I'd like to remind folks about
 the value of #3 ... arguably the dominant factor when it comes to the
 world's most prevalent CPU: the humble microcontroller. This is why
 'const' is oft discussed in terms of "storage class".

Very true.
 I'm tempted to argue that only #3 has the right to be called 'const',
 since #1 is handled by folding, or enum, or whatever, and #2 should be
 handled by the 'in' keyword ...

I have not much experience in microcontrollers, but where would be the difference to normal programs that may also have read-only data segments? Is there need to directly handle references to read-only memory? Call by reference would not be a problem, since that would be handled by the 'in' modifier. But would you need "pointer to const" as an explicit data type?
May 26 2004
parent reply "Kris" <someidiot earthlink.dot.dot.dot.net> writes:
"Norbert Nemec"  wrote
 I have not much experience in microcontrollers, but where would be the
 difference to normal programs that may also have read-only data segments?
 Is there need to directly handle references to read-only memory? Call by
 reference would not be a problem, since that would be handled by the 'in'
 modifier. But would you need "pointer to const" as an explicit data type?

My experience vis-a-vis MCUs pertains purely to the use of const as a RO segment identifier, so I'd be tempted to say no. I wonder if some Harvard-style architectures might benefit from what you suggest? Too many options ... (BTW, using 'const' to isolate entire fonts/resources into ROM on a device with 2K RAM is a blissful convenience). - Kris
May 26 2004
parent Norbert Nemec <Norbert.Nemec gmx.de> writes:
Kris wrote:

 "Norbert Nemec"  wrote
 I have not much experience in microcontrollers, but where would be the
 difference to normal programs that may also have read-only data segments?
 Is there need to directly handle references to read-only memory? Call by
 reference would not be a problem, since that would be handled by the 'in'
 modifier. But would you need "pointer to const" as an explicit data type?

My experience vis-a-vis MCUs pertains purely to the use of const as a RO segment identifier, so I'd be tempted to say no. I wonder if some Harvard-style architectures might benefit from what you suggest? Too many options ... (BTW, using 'const' to isolate entire fonts/resources into ROM on a device with 2K RAM is a blissful convenience).

I think that concept of 'const' goes along very well with the concept of 'const' for values that can be calculated at compile time. Just leave it to the compiler to decide whether some data needs some physical (RO-)memory, or whether it can just be used like any literal. If you have a const struct, it does not automatically need to be allocated in ROM. And if the compiler decides that there is need to have it as data in memory explicitely, it can simply allocate it in ROM.
May 26 2004