March 23, 2007
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, and from a couple of posts I understand that this is a source of confusion.
> 

Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".

> 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.
> 

Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"?

  A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1.

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 23, 2007
Walter Bright wrote:
> Bruno has answered your specific questions, so I'll take a more general tack.
> 
> A symbol is a name to which is 'bound' a value.
> 
> static int x = 3;
> 
> '3' is the value.
> 'int' is the type.
> 'x' is the symbol.
> 'static' is the storage class.
> 
> Here, we bind a new value to the symbol x:
>     x = 4;
> 
> 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
> 2) a type is independent of storage class, i.e. you cannot create a type that is "pointer to static" or "array of extern". Storage classes do not affect overloading, nor type deduction.
> 
> 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination.
> 
> 'invariant' is a guarantee that any data of that type will never change. '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).

So 'final' will be a storage class and not a type modifier? That's one of the questions I still have with regards to your design, because I'm not seeing how 'final' can also not-be a type modifier. In particular, again, what is
  typeof(&foo)
where foo is:
  final Foo foo;
?

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 23, 2007
Bruno Medeiros wrote:
> 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, and from a couple of posts I understand that this is a source of confusion.
>>
> 
> Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".
> 
>> 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.
>>
> 
> Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"?
> 
>   A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1.

That is what really happens, but won't help understanding references. So  it is not useful for that purpose.

Andrei
March 23, 2007
Daniel Keep wrote:
> 
> 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
> 

No, another way to solve that is to have 'final' be a type modifier as well:

  typeof(&foo)  --> (final Foo)*

This is essentially exactly like C++'s 'const'. (and like the 'rdonly' in my "hobbyist" design.)

-- 
Bruno Medeiros - MSc in CS/E student
http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
March 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Bruno Medeiros wrote:
>> 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, and from a couple of posts I understand that this is a source of confusion.
>>>
>>
>> Huh, " "Assign" doesn't quite catch the notion of indirect reference", what do you mean by that? I too was thinking that "assign" is a much better term than "binding".
>>
>>> 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.
>>>
>>
>> Dear Gods. Yes, that conceptualization is correct, but again, how is it any better than "assign"/"assignability"?
>>
>>   A very useful way to see "int x = 4;" is that the symbol x is assigned to the value 4. You can reassign x by writing ++x. That assigns x to the value x+1.
> 
> That is what really happens, but won't help understanding references. So  it is not useful for that purpose.
> 
> Andrei

Yes, that you've said already, what I would like to know is why. :P
What's the issue with assign and references?

-- 
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:
>> 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.
> 

Actually, having thought over it a few times, what I would really expect is not a "const pointer to a Foo", but rather a "const(pointer to a Foo)"...

final Foo foo;

auto ptr = &foo; // const(Foo*)

Hmm.  Baffling.  I almost give up.

-- Chris Nicholson-Sauls
March 23, 2007

Bruno Medeiros wrote:
> Walter Bright wrote:
>> Bruno has answered your specific questions, so I'll take a more general tack.
>>
>> A symbol is a name to which is 'bound' a value.
>>
>> static int x = 3;
>>
>> '3' is the value.
>> 'int' is the type.
>> 'x' is the symbol.
>> 'static' is the storage class.
>>
>> Here, we bind a new value to the symbol x:
>>     x = 4;
>>
>> 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
>> 2) a type is independent of storage class, i.e. you cannot create a
>> type that is "pointer to static" or "array of extern". Storage classes
>> do not affect overloading, nor type deduction.
>>
>> 'invariant' and 'const' are type modifiers (aka type constructors), which mean when they are applied to a type, a new type is created that is a combination.
>>
>> 'invariant' is a guarantee that any data of that type will never change. '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).
> 
> So 'final' will be a storage class and not a type modifier? That's one
> of the questions I still have with regards to your design, because I'm
> not seeing how 'final' can also not-be a type modifier. In particular,
> again, what is
>   typeof(&foo)
> where foo is:
>   final Foo foo;
> ?

I imagine it would be (invariant Foo*): an invariant pointer to a reference to a Foo.  Since *no one* is ever allowed to change final storage, then a pointer to it must be invariant.

	-- 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:
> Daniel Keep wrote:
>>
>> 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
>>
> 
> No, another way to solve that is to have 'final' be a type modifier as well:
> 
>   typeof(&foo)  --> (final Foo)*
> 
> This is essentially exactly like C++'s 'const'. (and like the 'rdonly'
> in my "hobbyist" design.)

I think the problem with that is that

  final pi = 3.1415...;

then doesn't do what you think it does.  If pi is now of type final real, then you would still be able to re-assign it.

  final e = 2.14...;
  pi = e;

We probably *could* make it so that you can't assign to a variable that's got a final'ed type, but then it's acting like a storage class, not as a type.

I dunno.  This whole thread is just giving me a headache... I *thought* I understood it after the first post, but now my head hurts and I'm not so sure :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 24, 2007
Chris Nicholson-Sauls wrote:
> Bruno Medeiros wrote:
>> 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.
>>
> 
> Actually, having thought over it a few times, what I would really expect is not a "const pointer to a Foo", but rather a "const(pointer to a Foo)"...
> 
> final Foo foo;
> 
> auto ptr = &foo; // const(Foo*)
> 
> Hmm.  Baffling.  I almost give up.

Don't. It's entirely understandable to be confused. Extremely little information has been given to date. Once that information will come in proper book format, it will be very easy to understand.

Andrei
March 24, 2007
Andrei Alexandrescu (See Website For Email) Wrote:
> We have talked about a design. In short, the intent is to define three flavors of immutability:
> 
> a) final - a simple storage class controlling the immutability of the bits allocated for the symbol per se;
> 
> b) const - type qualifier meaning an immutable view of an otherwise modifiable data. const does not control the bits of the object, only the storage addressed indirectly by it (transitively);
> 
> c) "superconst" - denoted as "const!" or "super const": type qualifier meaning that the data is genuinely unmodifiable.
> 

'invariant' seems to be the consensus (instead of super const or const!)? If so, I'd agree that's the best of the three.

> There is talk about deprecating lazy if it's best implemented via other mechanisms. There is also talk about deprecating "inout" in favor of "ref" on grounds that the often-useful "inout const" is likely to become #1 reason for bashing D.
>

I haven't noticed 'ref' come-up on subsequent posts, but I would strongly favor this change as well.

- Dave