March 16, 2007
Don Clugston wrote:
> My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++,  "constant" means "it will not change".
> 
> Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change.
> 
> Suppose in a function, you have 'const' access to a global variable.
> Another thread with write-access to that variable can change it, while the function is executing.
> 
> It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value.
> But that's not a constant in any reasonable sense of the word.

The difference between math and computer memory is that all too often in the latter case you want to express modular separation very often. Modular separation (in this context) means that the right to modify a certain object is owned by some part of program, and other parts may be offered only a view of that memory. This is such an important concept, even C adopted it. All of C's library functions that take pointers are anontated in their signature to specify whether or not they modify their input or not.

You want to enforce modular mutability cheaply. If D's immutability features fail to achieve that, we've done nothing.


Andrei
March 16, 2007
Derek Parnell wrote:
> On Fri, 16 Mar 2007 02:25:24 -0700, Andrei Alexandrescu (See Website For
> Email) wrote:
> 
>> Derek Parnell wrote:
>>>>> int a;
>>>>> const! int* p = &a; // error! cannot convert int* to const! int*
>>>>> final int b = 42;
>>>>> const! int* p1 = &b; // yah, b is truly immutable
>>>>> const! int* p2 = new const! int; // yah
>>> I'm not sure about that last one. Does this mean that p2 points to an int
>>> that cannot change and p2 itself can no longer be changed? And what is the
>>> value in the int that p2 points to?
>> Good point. 
> 
> <G> But you didn't answer my question? What is the value of the int to
> which p2 is pointing?

The default value of int, which is zero.

>> There is a little exception here. 
> 
> Oh no ... alarms start to sound when I see 'exceptions'. Is it not possible
> to eliminate this exception?

I would love to. It is only for the sake of compatibility with existing code.

>> People expect that when they write:
>>
>> const char[] str = "Hi!";
>>
>> they can't modify str nor its characters. So they expect str to be final as well. We then arrange that if const appears in a data definition, that data is automatically made final as well. So the above is equivalent to:
>>
>> final const char[] str = "Hi!";
> 
> Are you saying "People expect that when they write ... and so that's what
> we are going to have D do for them."?

I was just trying to minimize the amount of broken code. Also, we need to figure what to do about this:

const int capacity = 80;

In this context const makes no sense because int does not contain pointers. The above should be:

final int capacity = 80;

> Let's see if I got this ...
> 
>   const char[] str = "Hi!";  // Neither 'str' nor it contents can
>                              // be changed.
>   final const char[] str2 = "Hi again"; // Means the same as above syntax.

Correct.

>   const char*  chr = "Hi!";  // 'chr' can be changed but the chars
>                              // it points to cannot be changed.

Correct. The pointer can be made to point anywhere, but it's looking, no touching.

>   final const char*  chr2 = "Hi!";  // 'chr2' can be not be changed
>                                // and neither can its chars.

Yes.

> I hope I got this wrong because that is a easy bug maker.

How would the bugs be introduced?

>> If you don't want str to be final, do this:
>>
>> const(char[]) str = "Hi!";
> 
> You have got to be kidding! This is starting to get unreadable again. As a
> simple person, if I didn't want something to be 'final', I wouldn't use the
> 'final' keyword.

The problem is that many simple persons have different simple needs.

The parens actually help readability a lot when compared to C++ because you don't need to put several const's for complex types.

> But you are saying that if I don't want 'final', I not
> only have to avoid using 'final', I also have to put some of the phrase
> (and I know I'll never remember which parts) in parenthesis. But wait ...
> there's more. If I do want it to be 'final' all I have to do is not use the
> 'final' keyword.  Am I getting this right?
> 
> Is it not possible to make reading code simple?

An intuition that I see reasonable is that const by default engulfs everything to its right:

const char[] str = "Hi!"; // same as const(char[] str) = "Hi!";

When it engulfs the symbol, it makes it immutable, hence final. So by putting the parens you limit const's power.

But I'd be glad to drop this exception. I'm not sure what Walter and people who'll have to modify their code would say though.

>>> Hmmmm... does "const char[] X" mean that X.ptr can change, X.length can
>>> never change and the data pointed to by X.ptr can never change? Or is "can
>>> never" too strong? Is it more that code within the scope of the declaration
>>> is not allowed to change those things?
>> See the exception above. 
> 
> The EXCEPTION (alarms still ringing)  seems to be saying that 'const char[]
> X' means that X.ptr, X.length and the data in X's RAM cannot be changed.

I am hearing it. :o)

>> But now consider a function:
>>
>> void say(const char[] data)
>> {
>>    ...
>> }
>>
>> The bits of data are a private copy of say, so they can be changed discretionarily (if that's a word). But the bits pointed to by data do not belong to say, so they can't be written.
>>
>> If say wants to be fancy, it can look like this:
>>
>> void say(final const char[] data)
>> {
>>    ...
>> }
> 
> That didn't help. I'm even more confused now. Can I try? ...
> 
>   void say (const char[] data)
>   {
>      data[0] = 'a'; // Allowed but not passed back to caller.
>      data = "ABC";  // Not allowed.
>   }

Now, you got it backwards: data's contents belong to the caller, and data's pointer belongs to the callee.

>> Then data can't be even rebound. The "final" being a storage class, it doesn't appear in the function signature (e.g., in the interface file).
> 
> Hmmmm ... won't that cause problems for library writers who provide a
> library and ".di" files?

No.


Andrei
March 16, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Don Clugston wrote:
>> My problem is, I don't see any connection between "don't touch" and "constant" except that C++ got them confused. In every other other context outside of C++,  "constant" means "it will not change".
>>
>> Mathematically, you can "hold something constant" (even though it is actually a variable), but as long as it is being held constant, it can't change.
>>
>> Suppose in a function, you have 'const' access to a global variable.
>> Another thread with write-access to that variable can change it, while the function is executing.
>>
>> It makes sense for a function to have read-only access to a variable, and need to obtain a mutex when it wants to obtain the current value.
>> But that's not a constant in any reasonable sense of the word.
> 
> The difference between math and computer memory is that all too often in the latter case you want to express modular separation very often. Modular separation (in this context) means that the right to modify a certain object is owned by some part of program, and other parts may be offered only a view of that memory. This is such an important concept, even C adopted it. All of C's library functions that take pointers are anontated in their signature to specify whether or not they modify their input or not.
> 
> You want to enforce modular mutability cheaply. If D's immutability features fail to achieve that, we've done nothing.

I don't think he's arguing against immutable views, just against calling it 'const' ;).

In his words, from an earlier post:
=====
Don Clugston wrote:
> IMHO (b) should be 'readonly' and (c) should be 'const'.
> But this may be because I'm a physicist, and for me a constant is
> something like the speed of light, and C++'s const_cast always seemed
> utterly nonsensical.
>
> void alabama() {  // Actually compiles! Someone should be shot for this.
>    const double PI = 3.14159265358;
>    *const_cast<double *>(&PI) = 4.0;
> }
>
> Whereas 'readonly' seems to be a much better match for (b). Although
> it's an extra keyword, it seems to me that the concept discussed here is
> sufficiently fundamental to justify an extra keyword. Especially if we
> have a chance to rid of 'lazy'.
=====


In fact, I think most people here will agree that the ability for a function to specify "I won't modify this" enforced by the compiler (modulo pointer casts etc.) is a good thing. Especially if, as you mentioned, the function can return an (im)mutable result depending on whether a parameter was (im)mutable without having to rewrite the function, since that seems to be the biggest annoyance about C++'s constness system.
March 16, 2007
mike wrote:
> Am 16.03.2007, 10:19 Uhr, schrieb Andrei Alexandrescu (See Website
> For Email) <SeeWebsiteForEmail@erdani.org>:
> 
>> You can use "super const". We should be really really careful about
>>  adding new keywords; D already has tons, and I have a feeling we
>> don't want it to become Cobol or dBase.
>> 
>> If there are ways to stay away from new keywords, we'll do so. I do
>>  realize that no matter the syntax, there will be people who won't
>> like it. But avoiding adding keywords liberally is an overriding
>> desideratum.
>> 
>> 
>> Andrei
> 
> Why not "const final" or "final const"?
> 
> (a) .. final (b) .. const (c) .. const final / final const

Because final const and super const express very different realities.

> "super" is for calling constructors and that should be the only use
> for this keyword.

From your email I see you are Austrian, so I'm surprised. :o) German is the most synthetic (as opposed to analytical) language in use, and has the admirable property of building precise terms by combining smaller polysemous terms.


Andrei
March 16, 2007
Dan wrote:
> I think if we properly use 'const' to define something as 'not
> moving', and 'final' to define something as being 'unchangeable' then
> you can declare final const x and be done with it.
> 
> The simpler the language is, the better.

Simplistic does not mean simpler. Your system would be unable to express the simplest realities:

void print(const char[] message); // not modifying message

void main()
{
  char[] myMessage = readln();
  print(myMessage); // error! myMessage is changeable!
}

I truly think we've distilled the simplest language within our requirements.

Andrei
March 16, 2007
Benji Smith wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)
>>
>> Andrei
> 
> Really? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).
> 
> Let me join the ranks of those who hate both versions of the new syntax.  const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser. But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it.
> 
> Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts.
> 
> (By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc).
> 
> I vote for "readonly" and "const". Anything else seems like a mistake.

I think that sums up my take on this pretty well. Thanks for saving me the typing :).
March 16, 2007
I should also add that, in my opinion, any design where "const" means something other than "value resolved at compile time and immutable at runtime" would be a mistake.

(I'm not crazy about using "const" to mean "value resolved at runtime, and immutable after its first assignment", but I don't hate it either.)

--benji
March 16, 2007
Deewiant wrote:
> Benji Smith wrote:
>> And the word "super" is now overloaded in two completely unrelated concepts.
>>
> 
> Which isn't that rare, see the following link:
> http://www.prowiki.org/wiki4d/wiki.cgi?LanguageSpecification/KeywordIndex
> 
> I find the following examples: auto, in, is, mixin, scope, static.
> 
> I have come to abhor the keyword "static" largely due to the above. Too bad its
> various uses are unavoidably useful. <g>
> 
> But I do agree with you, in a way. After writing the following I find my
> explanation somewhat unclear even to myself, but bear with me.
> 
> The problem with "super const" is that "super" modifies the other keyword,
> "const", instead of saying something about the expression/statement/whatever (in
> this case, the type). Even "static", in all its horror, can be seen as
> specifying one of "module-level" or "compile-time". The other keywords mentioned
> above use their English meaning as such an explanation, and so can be understood
> without too much thought. "super const" would make "super" another "static":
> lacking context, you can't be sure about about even the general meaning, let
> alone the one in a specific instance.
> 
> Upon reflection it may be moot, since one probably rarely cares about keywords'
> meanings without context, but I'm sure some psychologist could come up with
> something about intuitiveness which affects coding speed, or whatever.

Working in NLP myself, I totally disagree. Natural language is rife with homonimy and synonimy, and we're all very, very happy with that. But in this case we don't even have to go that far: "super" is an adjective meaning primarily "of high grade or quality" and qualifies a noun. If there's no noun, you don't know what is "of high grade or quality". It's a fact, and we don't even blink.

The reality behind super const is that it expresses a stronger form of const. It makes a lot of sense if I dub it "super const" in natural language, to express it in the same way in the programming language. I thought that that's too verbose and devised "const!" as a shortcut (again with obvious conotations in natural language), but I'm thinking of dropping it and let type inference add "super" to "const" whenever it can. That should ensure exactness of the type system without verbosity in source code.

> I'd be happiest to just get the feature as soon as possible; worrying about
> keyword semantics can come later. Just like the abominations beginning with
> "on_scope_". <g>

Great idea. :o)


Andrei
March 16, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Derek Parnell wrote:
>> Yes! "const!" is bad form. Really bad. Horrible in fact. Just make it a new
>> keyword please, without using non-alpha characters. Such as "readonly",
>> "immutable", "keepyourgrubbyhandsoff", ... anything but using "!".
> 
> You can use "super const". We should be really really careful about adding new keywords; D already has tons, and I have a feeling we don't want it to become Cobol or dBase.
> 
> If there are ways to stay away from new keywords, we'll do so. I do realize that no matter the syntax, there will be people who won't like it. But avoiding adding keywords liberally is an overriding desideratum.
> 
> 
> Andrei

So instead of making D like Cobol we make it like APL ? :/
I don't think the problem of Cobol was *having* too many keywords, but rather forcing you to *use* lots of keywords for the simplest things. (Disclaimer: I don't actually know Cobol, I'm imagining it to be like Pascal, but worse)
So we should have that in consideration when talking about D. In fact, I think that any general idea of "adding more keywords is bad" is somewhat pernicious: every case should be examined in itself. In some cases it could be worth it, in others not.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 16, 2007
Benji Smith wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> We've shoved keywords like "readonly" and "view" for a while, and they just added more confusion than cleared, at a high cost. If (as I suspect) super const appears relatively infrequently, it might be fine to just encode it as the mildly verbose "super const". In fact, it's shorter than "keepyourgrubbyhandsoff". :o)
>>
>> Andrei
> 
> Really? I'd think super const would be used all the time. Anywhere a class has some invariant field, it'll probably be expressed as super const (if I'm understanding correctly that super const is the equivalent of #define constants in C++ or static final constants in Java).

No. super const deals with pointers and transitivity. Final deals with non-rebindable symbols. I'd be hard pressed to think of many examples where class members are transitively immutable.

> Let me join the ranks of those who hate both versions of the new syntax.  const! looks either like a template or like "not const". You guys may think you're saving a keyword, and that might be technically correct from the perspective of the parser.

The parser has zilch to do with it.

> But, for the perspective of the D developer, it still looks like you've introduced a new keyword, but it's a keyword that's A) nearly identical to another keyword, and B) contains a symbol. Ugh. I really. Really. Really. Hate it.

Can't help. For any given feature, there will be people who hate it. Usually they are also the most vocal :o).

> Using "super const" is also annoying because all of the other storage classes use a single keyword. Now we've got this weird case that uses two keywords. And the word "super" is now overloaded in two completely unrelated concepts.

So what? Don't we use words in natural language that are polysemous too? As long as the context makes it unambiguous, great.

> (By the way, I don't like "static if" either. I think the right choice would have been #if, #foreach, etc. And I think C++ made a mistake by defining "long long" and "double double" types as well. Presumably, that saved some keywords, but we'd all have been better off if the types were defined as int8, int16, int32, int64, float32, float64, etc).

You're making my point exactly. I love static if, and don't like #if. Again: for each feature, there will be people who like it and hate it :o).

> I vote for "readonly" and "const". Anything else seems like a mistake.

Which is which? How would you have people distinguish them without running to the manual? How would you explain C++ immigrants that const is actually readonly, and there is a const, but that const means something else than their const?


Andrei