March 22, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> sclytrack wrote:
>>> IMHO (b) should be 'readonly' and (c) should be 'const'.
>> [snip]
>>
>> vote++
>>
>>
>> Keywords
>> --------
>>
>> I also think keywords can be written attached to one another.
>> Like if you were to really call it "super const" have it called
>> superconst instead of super_const.
> 
> Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on.
> 
> superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.
> 
>> It is like the foreach_reverse that we have in D. Why not
>> call it foreachreverse instead.
> 
> Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
> 
> 
> Andrei

How about the '1984' syntax?

double + const int; // very very const
double + super();   // call parent-of-parent constructor

(just kidding!)

I've read the description of the three const types and it's not clear to me which is which.  It seems like being "immutable per se" (final) and "genuinely unmodifiable" are pretty much synonymous.

This may seem backwards, but it would help me to keep them apart if I knew how they were implemented (semantically, not necessarily in terms of code generation).


As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button.  The data is live but "under glass".

"final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data.  Almost like a #define, except that you can take the address of it.

"invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data.


I'm guessing that volatile only affects const.  An invariant object doesn't need it and a 'final' is also essentially compile time foldable and thus might not even be loaded from memory per se.  (Eventually, and subject to quality of implementation, etc.)  But before/after a volatile block, a normal "const" might need to be refreshed from memory in case someone else had updated?


(Feel free to tell me that some of this has been answered, and I'll look over the thread again.)

Kevin

March 22, 2007
Bill Baxter wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Bill Baxter wrote:
>>> Andrei Alexandrescu (See Website For Email) wrote:
>>>> sclytrack wrote:
>>>>>> IMHO (b) should be 'readonly' and (c) should be 'const'.
>>>>> [snip]
>>>>>
>>>>> vote++
>>>>>
>>>>>
>>>>> Keywords
>>>>> --------
>>>>>
>>>>> I also think keywords can be written attached to one another.
>>>>> Like if you were to really call it "super const" have it called
>>>>> superconst instead of super_const.
>>>>
>>>> Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on.
>>>>
>>>> superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.
>>>>
>>>>> It is like the foreach_reverse that we have in D. Why not
>>>>> call it foreachreverse instead.
>>>>
>>>> Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
>>>
>>> So you mean foreach(reverse) then?  I do like that!  You're right that it is quite D-like.  Too bad you weren't around back when foreach_reverse was introduced?   ;-)
>>
>> Possibly even without the parens:
>>
>> foreach (i ; array) { ... }
>>
>> foreach reverse (i ; array) { ... }
>>
>> I have a feeling Walter is unlikely to change that though :o).
>>
>>
>> Andrei
> 
> Except then 'reverse' would have to be a keyword too, no?

I think the theory is that, like scope(exit), where the 'exit' is not really a keyword, in the foreach xyz (...) {...} expression, there is no legal token that can go where 'xyz' is, so something there doesn't need to be special.  You could use "i" or "main" without conflicting with a variable or function name, for instance, because those can't appear there.

It's only in places where a user-defined identifier is legal that a given 'adjective' word needs to be keywords.  You could define this:

if and only if () {}  while away the hours () {}

... and not conflict with existing variables named (and, only, away, the, hours).

Kevin

> 
> --bb

March 22, 2007
Kevin Bealer wrote:
> As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button.  The data is live but "under glass".
> 
> "final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data.  Almost like a #define, except that you can take the address of it.
> 
> "invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data.

Swap these two names.

Andrei
March 22, 2007
Kevin Bealer wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> sclytrack wrote:
>>>> IMHO (b) should be 'readonly' and (c) should be 'const'.
>>> [snip]
>>>
>>> vote++
>>>
>>>
>>> Keywords
>>> --------
>>>
>>> I also think keywords can be written attached to one another.
>>> Like if you were to really call it "super const" have it called
>>> superconst instead of super_const.
>>
>> Yet you write static const not staticconst; public static not publicstatic; static if and not staticif; and so on.
>>
>> superconst came up too. But it creates a bad precedent. A healthier precedent is to synthesize phrases, not new keywords, from the existing keywords. Think of "static if" or "final switch". Very beautiful.
>>
>>> It is like the foreach_reverse that we have in D. Why not
>>> call it foreachreverse instead.
>>
>> Probably it's best to call it foreach reverse. It's unambiguous, easy to parse, does not add new keywords, and continues another nice precedent set by extern(language) and by scope(exit).
>>
>>
>> Andrei
> 
> How about the '1984' syntax?
> 
> double + const int; // very very const
> double + super();   // call parent-of-parent constructor
> 
> (just kidding!)
> 
> I've read the description of the three const types and it's not clear to me which is which.  It seems like being "immutable per se" (final) and "genuinely unmodifiable" are pretty much synonymous.
> 
> This may seem backwards, but it would help me to keep them apart if I knew how they were implemented (semantically, not necessarily in terms of code generation).
> 
> 
> As I understand it, "const" means "readonly view of something", similar to C++'s const but without the big "disable me" button.  The data is live but "under glass".
> 
> "final const" means the compiler never generates code to modify the underlying data and can assume (cache, do constant folding on) the underlying data.  Almost like a #define, except that you can take the address of it.
> 
> "invariant" is just like const, but refers to the symbol (and by extension the data) rather than just the data.
> 
> 
> I'm guessing that volatile only affects const.  An invariant object doesn't need it and a 'final' is also essentially compile time foldable and thus might not even be loaded from memory per se.  (Eventually, and subject to quality of implementation, etc.)  But before/after a volatile block, a normal "const" might need to be refreshed from memory in case someone else had updated?
> 
> 
> (Feel free to tell me that some of this has been answered, and I'll look over the thread again.)
> 
> Kevin
> 

Disclaimer: My current best understanding.

Final -> You may not re-bind/re-assign to this symbol.  The data bound to this symbol (ie, the object, struct, array, etc) is fully mutable.  Its a storage class of the variable, and has no effect on the data itself.  Foldable if its value is a basic scalar, such as an int.

Const -> Part of the type, provides a read-only view into data owned by code elsewhere with a mutable referance.

Invariant -> Part of the type, guaranteed absolutely not to change.  Essentially a contract of sorts.. in fact, I'm starting to think of it as an invariant{} contract block which "simply" asserts the data is always in the same state as immediately after construction.


Side effects of combinations:

'final const' -> An unbindable read-only view.  Could be useful for passing read-only views of data by referance, ie: void foo (final const ref bar) -- foo cannot modify the data referanced by bar, nor can it reassign bar, which would've reassigned the original variable since its by ref.  (The data referanced is constant, the referance itself -- ie the symbol -- is not.)

'final invariant' -> Ultimate const'ness.  An unbindable variable whose value is a referance to unchanging data.

Man I can't wait for all this to finally ship, in the hopes that it will come along with a thorough user manual...

-- Chris Nicholson-Sauls
March 22, 2007
Bill Baxter wrote:
> Don Clugston wrote:
> 
>> The natural association is "const" == "never changes, under any circumstances". "readonly" == "don't touch".
>> Even for read-only memory, if you've ever used an EPROM burner, or flashed firmware, you know that someone can write to it. I've changed readonly memory, I've never changed a constant.
>> The concept of 'read-only' access is pretty widely understood.
> 
> I dunno about that.  Yes if you're talking about physical constants or constants like Pi, they never ever change.  But 'constant' is also used frequently in mathematics to mean something that's simply "not variable in the current context".  Like when doing partial differentiation with respect to y, all variables besides y are treated as constants.

I discussed that already. The proposed 'const' is variable in the current context, since (for example) another thread can change it.

If you read a value described as 'const', then read it again later, it is not safe to assume that it has not changed. Therefore, it is not constant in any meaningful sense.


> Also your definition of constant (i.e. something like Pi which absolutely cannot change) seems to be a more a replacement for the proposed 'final' as in 'final Pi = 3.14;' than for a reference whose referent cannot change.

True. I just can't see much use for 'const' as a keyword.

> So personally I'm of the opinion we should pick two words that make at least a modicum of sense in English, forget about what they might mean in C++ or Java or whatever, make sure the common one is short, easy to type, and easy on the eyes, and just go with it.
> 
> --bb
March 23, 2007
Tyler Knott wrote:
> Chris Nicholson-Sauls wrote:
>> As I understand, there will be an implicit cast of mutables to immutables, so assuming 'const' appears under 'invariant' in this list, I would expect|hope it to be 'const Foo*' so that it is passable to either 'const' or 'invariant' typed parameters.  Ie:
>>
> 
> Actually, I take back what I said in my previous post in this thread.  Taking the address of a final variable should always result in an invariant pointer.  The reason is that invariant references require the data they reference to never, ever change whereas const references expect the data they reference to be changed by other non-const/non-immutable references to that data.  Obviously, since const references can't guarantee the data they reference won't change they can't be cast to immutable references at all, but because const references can still guarantee they won't mutate the data they reference immutable references can be freely cast to const references.

Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 23, 2007
Tyler Knott wrote:
> Bruno Medeiros wrote:
>>
>> Huh? Wait a second, but won't D have the same issue, albeit with 'final'? For example, suppose you have:
>>   final Foo foo;
>> then what is:
>>   typeof(&foo)
>> ?
>>
> 
> invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation.  I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.

Let's suppose it's  const Foo*  (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with  const Foo*  you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.:

  final Foo foo;
  foo.x = 2;   // ok

  typeof(&foo) fooptr = &foo;
  (*fooptr.x) = 2;   // not allowed

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 23, 2007

Bruno Medeiros wrote:
> Tyler Knott wrote:
>> Bruno Medeiros wrote:
>>>
>>> Huh? Wait a second, but won't D have the same issue, albeit with
>>> 'final'? For example, suppose you have:
>>>   final Foo foo;
>>> then what is:
>>>   typeof(&foo)
>>> ?
>>>
>>
>> invariant Foo* or const Foo*, depending on whichever is most appropriate for the situation.  I'd guess that invariant Foo* would be the default because it's semantically closest to what is being expressed (a pointer to immutable data), though const Foo* is also allowable because you can't modify data through const pointers either.
> 
> Let's suppose it's  const Foo*  (the less restrictive option). Even so, you will be restricting the type more than necessary, thus loosing some range of freedom. Because with  const Foo*  you can't change members of Foo*, while with final Foo, you can change members of foo. I.e.:
> 
>   final Foo foo;
>   foo.x = 2;   // ok
> 
>   typeof(&foo) fooptr = &foo;
>   (*fooptr.x) = 2;   // not allowed

I guess the only way to solve that is to parameterise const and invariant...

> final Foo foo;
> final invariant Foo bar;
> writefln("%s", typeinfo(typeof(&foo)));
> writefln("%s", typeinfo(typeof(&bar)));
>
> --> invariant(1) Foo
>     invariant(*) Foo

Honestly, I don't think that's going to happen :P

	-- Daniel

-- 
int getRandomNumber()
{
    return 4; // chosen by fair dice roll.
              // guaranteed to be random.
}

http://xkcd.com/

v2sw5+8Yhw5ln4+5pr6OFPma8u6+7Lw4Tm6+7l6+7D i28a2Xs3MSr2e4/6+7t4TNSMb6HTOp5en5g6RAHCP  http://hackerkey.com/
March 23, 2007
Bruno Medeiros wrote:
> Well, yes, but is 'invariant' transitive like const? I think it is (but I'm not sure, I'm getting a bit lost in the thread), and if it is, those semantics won't work. I.e., "typeof(&foo) " in my example can't be invariant anything.
> 

D'oh, of course!  It's legal to modify data referenced by foo, which makes it incompatible with invariant pointers, but which is fine for const pointers.  I think const pointer is the correct answer for typeof(&foo).
March 23, 2007
Derek Parnell wrote:
>> 'const' is a guarantee that any data of that type will never be modified through a reference to that type (though other, non-const references to that type can modify the data).
> 
>  const Foo f = new Foo("nice");
>        Foo g = f;
> 

Since the above case wasn't answered, I will. The "Foo g = f;" statement isn't allowed at all, because you are casting a const (think readonly) reference to a non-const reference. That isn't allowed, by design, since the very purpose of const (think readonly), is to disallow the holder of that reference to do any changes on the reference data.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D