March 21, 2007
Derek Parnell wrote:
> On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:
> 
> 
>> A symbol is a name to which is 'bound' a value.
>  ...
> 
>> Here, we bind a new value to the symbol x:
>>      x = 4;
> 
> I used to use the verb 'to assign' for this concept. I guess that's still
> okay or must I modernize <G>

You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion.

A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.

>> static int x = 3;
>>
>> '3' is the value.
>> 'int' is the type.
>> 'x' is the symbol.
>> 'static' is the storage class.
>>
>>
>> A storage class originally meant where the symbol is stored, such as in the data segment, on the stack, in a register, or in ROM. It's been generalized a bit since then. The main way to tell a storage class apart is that:
>> 1) a storage class applies to the symbol
> 
> "to the symbol"?  Don't you mean "to the data that the symbol represents"?
> In the case above, the symbol is 'x', and I don't think 'x' is being stored
> anywhere except in the compiler's internal tables, and I'm sure 'static'
> isn't referring to the compiler's internals.

The meaning was simple. When you say "poor fella Jim", "poor" applies to Jim, not to "fella".

>> 'invariant' is a guarantee that any data of that type will never change. 
> 
>  class Foo  {    int a;    char[] s;    this(char[] d)
>    {
>        s = d.dup;
>        a = s.length;
>    }
>  }
>  invariant Foo f = new Foo("nice");
> 
>  f.a = 1; // fails??? changing f's data
>  f.s = "bad"; // fails??? changing f's data
>  f.s.length = 1; // fails??? changing f's data
>  f.s[0] = 'r'; // okay ??? not changing f's data

They all fail. The last fails because invariance is transitive. All that could be done is to rebind f to another invariant object.


Andrei
March 21, 2007
Andrei Alexandrescu (See Website For Email) Wrote:

> (Reposted after cleanup :o))
> 
> kris wrote:
> > How about some further example? Given these sigs:
> > 
> > struct Foo
> > {
> >    int a;
> > }
> > 
> > class Bar
> > {
> >    char[] b;
> > }
> > 
> > void fooish (inout Foo foo) {}
> > 
> > char[] barish (Bar bar) {return bar.b;}
> > 
> > 
> > 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?
> 
> void fooish (const ref Foo foo) {}
> 


void fooish(const ref Foo foo) {
    foo.a = 1;                   // not allowed
    foo = sam_Foo;           // allowed?

jovo

March 21, 2007
On Tue, 20 Mar 2007 17:24:49 -0700, Andrei Alexandrescu (See Website For
Email) wrote:

> Derek Parnell wrote:
>> On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:
>> 
>>> A symbol is a name to which is 'bound' a value.
>>  ...
>> 
>>> Here, we bind a new value to the symbol x:
>>>      x = 4;
>> 
>> I used to use the verb 'to assign' for this concept. I guess that's still okay or must I modernize <G>
> 
> You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference,

Okay, if you say so, but I'm not having an issue with the concept of assigning value to something directly or indirectly.

> and from a couple of posts I understand that this is a source of confusion.

Not for me, but thanks anyway.

> A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5.

Huh? Just looks like a fancy way of saying 'x' first gets assigned the value 4 then later, using ++x, gets assigned the value 5. By whatever, I'll not get hung up as I think we are on the same track here.

> Once this is clear, the notions of values and references clarifies a lot.

It does? How? If pressed, I'd say that the only difference between 'assign' and 'bind' is that 'assign' maybe implies an 'assignment statement' was used to change the value, but 'bind' doesn't care how the change is caused.

>>> static int x = 3;
>>>
>>> '3' is the value.
>>> 'int' is the type.
>>> 'x' is the symbol.
>>> 'static' is the storage class.
>>>
>>>
>>> A storage class originally meant where the symbol is stored, such as in
>>> the data segment, on the stack, in a register, or in ROM. It's been
>>> generalized a bit since then. The main way to tell a storage class apart
>>> is that:
>>> 1) a storage class applies to the symbol
>> 
>> "to the symbol"?  Don't you mean "to the data that the symbol represents"? In the case above, the symbol is 'x', and I don't think 'x' is being stored anywhere except in the compiler's internal tables, and I'm sure 'static' isn't referring to the compiler's internals.
> 
> The meaning was simple. When you say "poor fella Jim", "poor" applies to Jim, not to "fella".

Oh, okay ... its not a 'static int' (a type) but a 'static x' (a value
represented by the symbol 'x').

>>> 'invariant' is a guarantee that any data of that type will never change.
>> 
>>  class Foo
>>  {
>>    int a;
>>    char[] s;
>>    this(char[] d)
>>    {
>>        s = d.dup;
>>        a = s.length;
>>    }
>>  }
>>  invariant Foo f = new Foo("nice");
>> 
>>  f.a = 1; // fails??? changing f's data
>>  f.s = "bad"; // fails??? changing f's data
>>  f.s.length = 1; // fails??? changing f's data
>>  f.s[0] = 'r'; // okay ??? not changing f's data
> 
> They all fail. The last fails because invariance is transitive. All that could be done is to rebind f to another invariant object.

Thanks. I'm just trying to get all this straight in my mind. So the definition should be more along the lines of ...

'invariant' is a guarantee that any data accessible from that type will never change.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Justice for David Hicks!"
21/03/2007 11:52:49 AM
March 21, 2007
Andrei Alexandrescu (See Website For Email) Wrote:
> You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, and from a couple of posts I understand that this is a source of confusion.
> 
> A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. Once this is clear, the notions of values and references clarifies a lot.
> 

Actually, when I use this term:

struct S {
    int a;
    int* b;
}

const S s;
s.a = 1;                        // not allowed
s.b = some_address;       // not allowed
*s.b = 1;                      // not allowed
s = some_S;                  // allowed

don't look alogical, and what is more important, produces, I think at first look, better result.

jovo



March 21, 2007
jovo wrote:
> Andrei Alexandrescu (See Website For Email) Wrote:
> 
>> (Reposted after cleanup :o))
>>
>> kris wrote:
>>> How about some further example? Given these sigs:
>>>
>>> struct Foo
>>> {
>>>    int a;
>>> }
>>>
>>> class Bar
>>> {
>>>    char[] b;
>>> }
>>>
>>> void fooish (inout Foo foo) {}
>>>
>>> char[] barish (Bar bar) {return bar.b;}
>>>
>>>
>>> 1) how do I modify the function decls to have the compiler *enforce* readonly upon the referenced content? e.g. Foo.a and Bar.b cannot be mutated within the function body?
>> void fooish (const ref Foo foo) {}
>>
> 
> 
> void fooish(const ref Foo foo) {
>     foo.a = 1;                   // not allowed

Not allowed indeed.

>     foo = sam_Foo;           // allowed?

Not allowed. The type of foo is const(ref(Foo)). When you try to assign to foo, you'll assign to indirectly referenced bits. If you only replace Foo with int (which makes sense because Foo is a struct), you'll see how trying to assign the int would indirectly modify memory outside the function.

Now consider:

void Fun(ref const Foo foo) {
}

The type of foo is ref(const(Foo)). So the function has a reference to a constant object. It can modify the direct fields of the object, but nothing beyond that. It's not a very useful case. We might even choose to prohibit it statically unless compelling use cases show up. I actually already think of a couple :o).


Andrei
March 21, 2007
Derek Parnell wrote:
> On Tue, 20 Mar 2007 17:24:49 -0700, Andrei Alexandrescu (See Website For
> Email) wrote:
> 
>> Derek Parnell wrote:
>>> On Tue, 20 Mar 2007 16:01:35 -0700, Walter Bright wrote:
>>>
>>>> A symbol is a name to which is 'bound' a value.
>>>  ...
>>>
>>>> Here, we bind a new value to the symbol x:
>>>>      x = 4;
>>> I used to use the verb 'to assign' for this concept. I guess that's still
>>> okay or must I modernize <G>
>> You may want to modernize. "Assign" doesn't quite catch the notion of indirect reference, 
> 
> Okay, if you say so, but I'm not having an issue with the concept of
> assigning value to something directly or indirectly.
> 
>> and from a couple of posts I understand that this is a source of confusion.
> 
> Not for me, but thanks anyway.
> 
>> A very useful way to see "int x = 4;" is that the symbol x is bound to the Platonic number 4. The 4 itself cannot change. You can rebind x by, say, writing ++x. That unbinds x from Plato 4 and binds it to Plato 5. 
> 
> Huh? Just looks like a fancy way of saying 'x' first gets assigned the
> value 4 then later, using ++x, gets assigned the value 5. By whatever, I'll
> not get hung up as I think we are on the same track here.
> 
>> Once this is clear, the notions of values and references clarifies a lot.
> 
> It does? How? If pressed, I'd say that the only difference between 'assign'
> and 'bind' is that 'assign' maybe implies an 'assignment statement' was
> used to change the value, but 'bind' doesn't care how the change is caused.

No. The difference is major. The binding to Platonic values clarifies that values are exactly the same thing as references to immutable objects. Once that is understood, it's very easy to understand all of D's immutability minutiae.


Andrei
March 21, 2007
Don Clugston wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Don Clugston wrote:
>>> Assuming that 'invariant' = really constant, 'const' = C++ pseudo-const...
>>
>> Yah.
>>
>>> It's better than super const. However:
>>> (1) I would want to go through all my existing D code and change 100%
>>> of my usages of 'const' to 'invariant'.
>>
>> Great to hear that!
> 
> Sorry, I didn't explain myself very well. I meant that this proposal breaks 100% of all existing D uses of const.
> 
>  >> (3) I concede the problem of association with 'readonly' and ROM. But
>>> the association between 'const' and 'constant' is pretty strong.
>>
>> I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.
> 
> I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch".

Indeed, and seems to represent a misunderstand of what const *does* mean in C++.

In this context:
  int const x(3);
it means "x is constant, i.e., cannot be changed".  In
this context:
  int const *y(&x);
it means "y is a pointer to a (possibly constant) int".
Without the const, y would not be allowed to point to
a constant int.  It doesn't mean "don't touch" -- it
means "cannot be used to alter", i.e., "leaves const
if indeed it was const".  It's closer to "won't touch".

It's clear though that the meaning confuses too many
people.  What's not clear to me is whether the proposed
terminology for D is any better.  Certainly much of
the discussion seems to be based on misstatements of
how C++ works.  There's scope to do better than C++,
but it does require understanding that on which we hope
to improve.

-- James
March 21, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Don Clugston wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> I think there's universal agreement that you can't express tersely the two notions "const-as-in-C++" and "const-as-in-we-really-mean-it". Probably it's best to just go with two terms and move on.
>>
>> I completely agree with this. The gripe I have is that 'const' is a completely inappropriate term for 'const-as-in-C++'. It's a bizarre misnomer to use 'const' to mean "don't touch".
> 
> The problem is that we don't have a "nomer". Every good short name we considered would be as imprecise or more. There's no obvious choice that everybody's like, "those idiots! why did they _refuse_ to do it that way?" And it's telling that every single person who didn't like "const" with the intended meaning failed to come with an obviously better choice.

Actually, I have not tried to come up with a better choice.
I still think 'readonly' captures it pretty well. I've changed my mind about the validity of the argument about "it's not obvious which means truly constant, 'const' or 'readonly'" since I feel that it applies just as strongly to 'const' vs 'invariant'.
My intuition would be that 'invariant' means read-only. The usage of 'invariant' in design-by-contract is for something that can be modified temporarily but must ultimately be preserved; this is weaker than 'constant'.

>> The only benefit (albeit a considerable one) of this nomenclature is compatibility with C++ nomenclature, especially the term "const correctness".
> 
> Right. Imagine us coming with the "dontouch correctness" :o).
> 
>> D currently has a 'const' which actually means "constant", it seems dreadful to exchange that for a clearly inferior "don't touch" meaning.
> 
> It's not "inferior". If it were inferior, we'd take it out of the language. Today's "const" semantics are restrictive in ways that severely limit its usefulness (e.g. you can't pass data modifiable in a module to functions guaranteed to NOT modify data in another module).
> The new const will allow that, and that's great. It's not inferior.

I'm arguing about the name, not the semantics. The use of 'const' in the original post has caused no end of confusion, since it is different from the current D const.
To rephrase:
'const' is a very appropriate word for what 'const' does in D now: it defines a constant. The proposed const has an inferior connection to the word 'constant'.

Actually, there's a feature of the existing const which seems to be missing in the new proposal.

Currently, if you have
const int x = 4;

it is illegal to write &x. (just as it is illegal to write &4).
This means that the existing const cannot be subverted, even by asm code. (#define x 4 is similar, except untyped). Can you do this with the new proposal?


>> I'm concerned that you may have spent so much time in C++ that you've become accustomed to "const" == "don't touch"; all of my previous posts have been arguing that this is a grossly unnatural association.
> 
> I completely hear you. Yet you are failing to follow with, "...when it's so obvious to everyone that the natural association is..."

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.

March 21, 2007
Tyler Knott wrote:
> Bruno Medeiros wrote:
>>
>> What?? If f is 'const', how are any of those "f.s =" assignments allowed?
>>
> 
> Because f is a POD (Plain Old Data) structure and not a reference you can modify the data in the structure, but because it's declared const you can't modify any data referenced.  If you want f.s to be unassignable then declare f to be final Foo, though you can then modify the data referenced by f.s so f.s[0] = 'a'; becomes legal.
> 
> For example:
> 
> struct Foo
> {
>     char[] s = "hello";
>     char c;
> }
> 

Duh, of course. I misread and was thinking Foo was a class and not a struct.



-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 21, 2007
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.

And if you don't agree with me, the very first section of the Wikipedia on "Constant" (http://en.wikipedia.org/wiki/Constant) talks about
"unspecified constants", referring to parts of an equation that simply aren't variables.  But you can definitely change them if you want (the example they use is the Pythagorean theorem).  They are only constant for one particular instance of the problem.   Even if the Wikipedia article is way off base (the Pythagorean theorem seems a very odd choice to demonstrate the concept of 'constant') the fact that such text managed to make it onto Wikipedia indicates that the common understanding of the word "constant" includes more territory than you're apparently allowing for.

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.

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