August 14, 2003
Antti Sykäri wrote:
> So the main question is, should one make a programming language that will make programming fun, or one that allows for as strict static guarantees as possible?

The C++ const doesn't make any strict static guarantees, that's why it's worthless for a compilers' optimizer and also why it ultimately is only an annoyance.

In C++, not only can anyone cast away constness, there's not even a
clear consensus on what actually *is* const. Some go for "no byte is
ever changed", some go for "no outside visible state is ever changed".
The latter in general makes more sense, but it implies that data members
of const classes *can* change (as long as it's invisible to the rest of
the world :), which in turn means that neither the compiler nor the
programmer can really rely on const meaning "nothing ever changes",
especially since both have their subtilities. Even a byte-by-byte const
class that never changes can actually change its state if it contains a
pointer to some non-const object that changes; and the other way round,
a conceptually const object can change its internal storage quite often :)

Add to that the several subtilities in C++ regarding const (things like the compiler implicitly converting values to const references if need be, which is useful, but somewhat awkward really) and I can very well understand why a compiler writer wouldn't see much benefit in it.

> Another could relying for run-time guarantees: placing the const data in a page with only read-only access, and turning hardware exceptions into D exceptions if possible. This is what C++ does (in addition to static guarantees of const) and that's my personal preference, too.

This does not work with the conceptual const-ness approach, which limits the usefulness of const quite dramatically.

-fg


August 15, 2003
"Fabian Giesen" <rygNO@SPAMgmx.net> a écrit dans le message de news:bhggt3$fiq$1@digitaldaemon.com...
> Antti Sykäri wrote:
> > So the main question is, should one make a programming language that will make programming fun, or one that allows for as strict static guarantees as possible?
>
> The C++ const doesn't make any strict static guarantees, that's why it's worthless for a compilers' optimizer and also why it ultimately is only an annoyance.
>

So IMO we need a way that allows us to tell the compiler that we want strict guarantees for some data...

> In C++, not only can anyone cast away constness, there's not even a
> clear consensus on what actually *is* const. Some go for "no byte is
> ever changed", some go for "no outside visible state is ever changed".
> The latter in general makes more sense, but it implies that data members
> of const classes *can* change (as long as it's invisible to the rest of
> the world :), which in turn means that neither the compiler nor the
> programmer can really rely on const meaning "nothing ever changes",
> especially since both have their subtilities. Even a byte-by-byte const
> class that never changes can actually change its state if it contains a
> pointer to some non-const object that changes; and the other way round,
> a conceptually const object can change its internal storage quite often :)
>

There we need a few keyword to denote each interesting cases...

We declaring data, we have a few possibilities:
- compile-time constants
- static constant data (always exists and with proper value)
- run-time constant data (const while object exists)
- non constant data

We passing data as parameter, we have 3 possibilities:

- we may want to allows modifications
- we don't want visible (state) modification
- we don't want any modification

We using data, we have 4 possibilities:

- the data is not const, we can modifie any way we want
- the data is declared const but not physically const, can be modified with
a cast
- idem but the data may also be modified externally...
- the data is physically const, cannot be modified even with a cast (this
could include compile-time constant and could help making meta-programming
easier by allowing function like syntax for integral types...)


IMO in, inout and out should be strict for parameters. That is, it should not be possible to modify in parameters.

We could uses "immuable" as a modifier to tell the compiler that it can assumes that the data won't be modified externally or alternatively "volatile" if the compiler should not assumes it (depending on what we prefer as the default - safer or faster) or maybe both. If immuable is supported, they we can const_cast regular in parameters...

For out and inout, we don't have the problem...For simplicity, we should always allows modifications (at the outer level).

In each cases, we may want to add modifier to data (and pointer member) of
class type arguments... so that some member may always be modified (mutable)
or never be modified (const).

When declaring data, immuable would mean that the data will never be modified (physically) while const would applys to visible state. For immuable data, the compiler would be allowed to optimize construction by optimizing the constructor to minimize run-time execution by doing compile-time initialisation if possible.

So in resume, my suggestion is that modifier works essentially as they do in C++ but we would have 1 more keyword to represent stricter constness and when data keyword is used, the compiler would not allows const_cast and assumes not external modifications except if the argument is declared also mutable).

Some examples to help clarify the idea (this is not a complete analysis)

void f1(in int a);    // a is const (similar to const & in C++ - if a is
modified, changes need not to propagate back but can)
void f2(in immuable int a);   // also physically const and const_cast not
allowed... (if we don't want 1 more keyword...)
void f3(in volatile int a);    // can be modified externally - compiler must
not optimize access

void f4(out immuable int a);    // cannot be modified externally

void f5(inout const int a);    // same as in int a but will always propagate changes back if const_cast is used...

Some other combinaisons are allowed and some are prohibited... It may be possible that some keyword impies other one (immuable implies const except for out parameter (if supported with the above meaning))

Some other keyword may also be used: byref (or &) and/or byvalue. Also, we
may have variable (or var) and we should also support the move-constructor
idiom with another keyword (transfert) or by a predefined operator (or
member)...

> Add to that the several subtilities in C++ regarding const (things like
the
> compiler implicitly converting values to const references if need be,
which
> is useful, but somewhat awkward really) and I can very well understand why a compiler writer wouldn't see much benefit in it.
>
> > Another could relying for run-time guarantees: placing the const data in a page with only read-only access, and turning hardware exceptions into D exceptions if possible. This is what C++ does (in addition to static guarantees of const) and that's my personal preference, too.
>
> This does not work with the conceptual const-ness approach, which limits
the
> usefulness of const quite dramatically.
>
> -fg
>
>


August 15, 2003
In article <bhggt3$fiq$1@digitaldaemon.com>, Fabian Giesen wrote:
> Antti Sykäri wrote:
>> So the main question is, should one make a programming language that will make programming fun, or one that allows for as strict static guarantees as possible?
> 
> The C++ const doesn't make any strict static guarantees, that's why it's worthless for a compilers' optimizer and also why it ultimately is only an annoyance.
> 
> In C++, not only can anyone cast away constness, there's not even a clear consensus on what actually *is* const. Some go for "no byte is ever changed", some go for "no outside visible state is ever changed".

There's no point arguing about the meaning of const, just look up the definition in the standard.  Which in this case says:

- trying to change any (member of an) object through a const-qualified
  access path (e.g. a pointer of type const T*) is an error
- however, you can work around the type system using const_cast<>
- but still, an attempt to change an const object results in undefined
  behavior

with the exceptions of mutable members, which you in fact can change.

So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.

-A.

August 16, 2003
> So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.

Unless someone casts your donstness away, which anyone can do without you ever knowing.

Which means that const is really just a vague promise.

-fg


August 17, 2003
I would vote that it would not be possible to cast away constness... but
then
the problem is that if someone forget some const in a library and I uses
that
library, I will not be able to call those functions..

In fact, it would preferable to have const by default and having to specify it explictly when we want to allows modification (this would also apply to member functions). For inout and out parameter, the rule would be different. If there are only one implicit-indirection level, that level would not be const.

Same for member functions....


Or better if it is possible would be that the default is detected by the
compiler
and user can add modifier if he want to force something. This could include
the possibility of byref, const, variable (var), constness_of, byvalue,
volatile,
mutable and immuable... (in addition to existing in, inout and out). Also,
we should be able to specify if null (empty, 0) is allowed and default.

I think that we should at least have the attribute that we can specify for parameters of a COM method in an IDL file.

When nothing is specified, value semantic would be used if the compiler
cannot prove that something won't get modified by an in parameter
(or by a member function call).


"Fabian Giesen" <rygNO@SPAMgmx.net> a écrit dans le message de news:bhmc8c$h12$1@digitaldaemon.com...
> > So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.
>
> Unless someone casts your donstness away, which anyone can do without you ever knowing.
>
> Which means that const is really just a vague promise.
>
> -fg
>
>


August 17, 2003
In article <bhmc8c$h12$1@digitaldaemon.com>, Fabian Giesen wrote:
>> So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.
> 
> Unless someone casts your donstness away, which anyone can do without you ever knowing.
>
> Which means that const is really just a vague promise.

You can be pretty certain that the callee won't cast your constness away without being sure that the object isn't actually const-qualified, since the object could be const-qualified and located in a read-only segment. If it is, trying to modify it through a non-const pointer will cause undefined behavior -- in practice, segmentation fault.

-Antti
August 17, 2003
"Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbjuvvn.man.jsykari@pulu.hut.fi...
> In article <bhmc8c$h12$1@digitaldaemon.com>, Fabian Giesen wrote:
> >> So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.
> >
> > Unless someone casts your donstness away, which anyone can do without you ever knowing.
> >
> > Which means that const is really just a vague promise.
>
> You can be pretty certain that the callee won't cast your constness away without being sure that the object isn't actually const-qualified, since the object could be const-qualified and located in a read-only segment. If it is, trying to modify it through a non-const pointer will cause undefined behavior -- in practice, segmentation fault.
>
I'm not sure a quite follow the argument here, and not all platforms seg
fault they may quitely not change things (Rom'ed object on an embedded
target).
 in all you are just justifying the point that c++ const is a meaninlessly
vague promise.
what it wanted is a concrete callee promise that they will not modify under
any condition
(the caller or other may [which is the root of the problem])


August 17, 2003
In article <bho1ia$2ro1$1@digitaldaemon.com>, Mike Wynn wrote:
> 
> "Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbjuvvn.man.jsykari@pulu.hut.fi...
>> In article <bhmc8c$h12$1@digitaldaemon.com>, Fabian Giesen wrote:
>> >> So the standard says that if we've got pointer to a const object, we can't change it, but does not indeed say the object would be immutable. Which is quite convenient: when you call a function with signature void f(const T*); you can be certain that it won't change your argument.
>> >
>> > Unless someone casts your donstness away, which anyone can do without you ever knowing.
>> >
>> > Which means that const is really just a vague promise.
>>
>> You can be pretty certain that the callee won't cast your constness away without being sure that the object isn't actually const-qualified, since the object could be const-qualified and located in a read-only segment. If it is, trying to modify it through a non-const pointer will cause undefined behavior -- in practice, segmentation fault.
>>
> I'm not sure a quite follow the argument here, and not all platforms seg
> fault they may quitely not change things (Rom'ed object on an embedded
> target).
>  in all you are just justifying the point that c++ const is a meaninlessly
> vague promise.
> what it wanted is a concrete callee promise that they will not modify under
> any condition
> (the caller or other may [which is the root of the problem])

It's just a question of the proportion of trust you are ready to place on the contract (or the promise) that the function declaration "f(const T*)" has. "I won't modify my argument."  The const keyword is a way to state that clearly and concisely.  If you would want to ban const_cast to make that a "concrete guarantee" instead of a promise, you'd have to ban unions, inline assembly, foreign function interfaces and all those good old dangerous features, because they can all be used to subvert constness.

As for the "vague promise" that const keyword gives...

Is it, by analogy, a "vague promise" that you will end up in jail if you commit a murder?  You might get away with it (if the police don't catch you or if you happened to cast away the constness of an object that actually wasn't const) or then you might get caught (if the object actually was in a read-only segment).

People don't usually go around killing other people, firstly because usually there's no particular reason to do that.  Secondly, doing that might have dire consequences -- undefined behavior if you will.  And you don't break the unspoken rules of a programming language either, or if you do, you face the consequences.

I'm not going to give any reasons why it would be a good idea for anyone to kill someone (we already had a religious discussion about goto; no need to bring abortion, euthanasia or death penalty into the picture now), but sometimes it's needed to cast away the constness and therefore C++ has standard, working, well-documented const_cast operator for that purpose.

Anyway, my point, if it didn't state it clearly enough, was that no one in their sane mind would do, for example, this:

cheater.h:
--------------------------
// I promise not to touch str
void cheater(const char* str);
--------------------------

cheater.cpp:
--------------------------
void cheater(const char* str)
{
        char* cheat = const_cast<char*>(str);

        // Ha-ha! A little trick, hopefully no one will notice.
        cheat[0] = 'x';
}
--------------------------

The reason being:

main.cpp:
--------------------------
#include "cheater.h"
#include "stdio.h"

int main(int argc, char* argv[])
{
        if (argc < 2)
                return 1;

        const char* str;

        if (strcmp(argv[1], "1") == 0)
        {
                const char const_string[] = "abc";
                str = const_string;
        }
        else if (strcmp(argv[1], "2") == 0)
        {
                char non_const_string[] = "abc";
                str = non_const_string;
        }
        else if (strcmp(argv[1], "3") == 0)
        {
                str = "abc";
        }

        cheater(str);
        printf("str = %s\n", str);
}
--------------------------

jsykari:~% mv a.cc main.cc
jsykari:~% g++ main.cc -o main
jsykari:~% ./main 1
str = xbc
jsykari:~% ./main 2
str = xbc
jsykari:~% ./main 3
zsh: segmentation fault  ./main 3

Whoops!

One of the general rules that guided the development of C++ was "Don't try to force people" (quote from D&E):

"Programmers are smart people. They are engaged in challenging tasks and need all the help they can get from a programming language as well as from other supporting tools and techniques. Trying to seriously constrain programmers to do "only what is right" is inherently wrongheaded and will fail. Programmers will find a way around rules and restrictions they find unacceptable."

I hope that D is not heading in a radically different direction.

Oh, and by the way, same applies for the dreaded goto statement.

-Antti

August 17, 2003
"Antti Sykäri" <jsykari@gamma.hut.fi> wrote in message news:slrnbjvjf1.pru.jsykari@pulu.hut.fi...
>
> "Programmers are smart people. They are engaged in challenging tasks and need all the help they can get from a programming language as well as from other supporting tools and techniques. Trying to seriously constrain programmers to do "only what is right" is inherently wrongheaded and will fail. Programmers will find a way around rules and restrictions they find unacceptable."
>
> I hope that D is not heading in a radically different direction.
>
> Oh, and by the way, same applies for the dreaded goto statement.
>
your whole argument would seem to me to agree that const is pointless, yet
you are argueing for it !
D does not have const params, and the above statement implies that it should
never have const params (or final [java]).

to me your argument actually agrees with "const it just a vague promise" so effectively useless.

and not all platform have exceptions on write to location 0; *((char*)0) =
'A'; can work
the same as on some platforms write into read only areas just has no effect.








August 18, 2003
Bill Cox wrote:
> I would be very interested in hearing about the utility of const.  I'm not disputing your assertion, but I haven't had the same experience.

It took me looooooong to remember... i was telling to myself all the time: there must be some use, there must be some use... and now i think i finally recall it!

Temporaries, generated in C++ expressions, are const. This has to be to insure they can be cleaned up correctly. That is, making a function work with const, makes it more flexible in respect to temporaries. I can recall similar rules for some circumstances in (IIRC) Delphi and certainly Sather.

I vaguely recall const solves thus memory leaks on temporaries. Maybe i've gotten something wrong. Just correct me. In D, this should be a non-issue because of GC -- except for performance.

And i still don't think i understand, what's the sense of casting away const-ness - we have our mutable fields. Can anyone come up with a sane example?

-eye