January 23, 2007
Frits van Bommel wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Frits van Bommel wrote:
>>> Deletion of a const reference will be necessary for const objects at the very least (since there are no non-const references to them). Presumably, that's what the "const destructor" is for.
>>>
>>> A case could be made for disallowing explicit deletion of const references, but that would mean const objects would only be deletable by the GC. That, in turn would mean const objects would be unusable by people who need (or just prefer) the GC to be disabled...
>>> Perhaps this should be more of a "best practice" instead of a language rule?
>>
>> Deletion of pointers to const data has always been a sticky issue in C++. There are good arguments either way. I think it should be disallowed, otherwise a caller passing a const class object does not have a guarantee that the callee didn't mutate the object, which is the very purpose of the entire scaffolding.
> 
> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).

I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:

Widget owned = new Widget;
const Widget publicized = owned;
... use publicized wherever ...
delete owned;

This is IMHO entirely reasonable.

> For that reason, I think it should maybe merely be very rude to delete a const reference unless you are absolutely sure nobody else has a reference to the object (that they will ever use), not an error.

I think this might be an acceptable solution, but given the choice, I'd stay away from it. I think the C++ experience hasn't shown delete const to have any desirable virtues.

Imagine a dialog like this:

"You shot a diplomat with immunity!"
"He's dead. A dead body can't have diplomatic immunity."
"But he was alive and immune when you shot him!"
"But at that point my bullet was in the gun."


Andrei
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
>> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
>> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).
> 
> I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:

<pedantic> I said const *objects*, not const references. </pedantic>

> Widget owned = new Widget;
> const Widget publicized = owned;
> ... use publicized wherever ...
> delete owned;
> 
> This is IMHO entirely reasonable.

Yeah, I guess it doesn't look that bad. Besides, I always keep the GC on anyway ;).

But I do think this is reasonably likely to become a FAQ.

>> For that reason, I think it should maybe merely be very rude to delete a const reference unless you are absolutely sure nobody else has a reference to the object (that they will ever use), not an error.
> 
> I think this might be an acceptable solution, but given the choice, I'd stay away from it. I think the C++ experience hasn't shown delete const to have any desirable virtues.
> 
> Imagine a dialog like this:
> 
> "You shot a diplomat with immunity!"
> "He's dead. A dead body can't have diplomatic immunity."
> "But he was alive and immune when you shot him!"
> "But at that point my bullet was in the gun."

LOL.

(Not sure it applies, but LOL none the less :) )
January 23, 2007
Frits van Bommel wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Frits van Bommel wrote:
>>> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
>>> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).
>>
>> I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:
> 
> <pedantic> I said const *objects*, not const references. </pedantic>

This is actually a great point. In the case of classes, is const a property of the value, or a property of the reference through which the value is accessed?

This philosophical-sounding question leads actually to radically different implementations. If you associate constness with the value, then you have true immutable values. This was, at a point in the history of humankind, Walter's opinion of a good starting point for talking about const: true ROMable values. However, that approach is too rigid to be useful: too rarely you have truly immutable data, but most often you want to make sure that certain parts of a system *think* data is immutable.

A relaxation of that concept therefore is to associate constness with the reference through which the value is accessed. Then you have much more flexibility in that you can have some mutable object, pass it to a function through a const handle (thus knowing that that function can never change it), and then continue enjoying mutable access to that object.

The downside of this relaxation is that aliasing might stick its nose. My conjecture is that in the vast majority of cases it can be trivially proved (by the compiler) that no aliased access can affect const data. And even in the cases where the compiler must generates conservative code (as it does today in 100% of the cases), the benefit to the programmer still justifies this more relaxed view of immutability.

So: class objects are never const. Const references only restrict access, not the nature of bits on the heap.


Andrei
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
> 
>> Andrei Alexandrescu (See Website For Email) wrote:
>>
>>> Frits van Bommel wrote:
>>>
>>>> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
>>>> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).
>>>
>>>
>>> I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:
>>
>>
>> <pedantic> I said const *objects*, not const references. </pedantic>
> 
> 
> This is actually a great point. In the case of classes, is const a property of the value, or a property of the reference through which the value is accessed?
> 
> This philosophical-sounding question leads actually to radically different implementations. If you associate constness with the value, then you have true immutable values. This was, at a point in the history of humankind, Walter's opinion of a good starting point for talking about const: true ROMable values. However, that approach is too rigid to be useful: too rarely you have truly immutable data, but most often you want to make sure that certain parts of a system *think* data is immutable.
> 
> A relaxation of that concept therefore is to associate constness with the reference through which the value is accessed. Then you have much more flexibility in that you can have some mutable object, pass it to a function through a const handle (thus knowing that that function can never change it), and then continue enjoying mutable access to that object.
> 
> The downside of this relaxation is that aliasing might stick its nose. My conjecture is that in the vast majority of cases it can be trivially proved (by the compiler) that no aliased access can affect const data. And even in the cases where the compiler must generates conservative code (as it does today in 100% of the cases), the benefit to the programmer still justifies this more relaxed view of immutability.
> 
> So: class objects are never const. Const references only restrict access, not the nature of bits on the heap.


All sounds good to me. Bring it on :D
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Frits van Bommel wrote:
>>>> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
>>>> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).
>>>
>>> I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:
>>
>> <pedantic> I said const *objects*, not const references. </pedantic>
> 
> This is actually a great point. In the case of classes, is const a property of the value, or a property of the reference through which the value is accessed?
> 
> This philosophical-sounding question leads actually to radically different implementations. If you associate constness with the value, then you have true immutable values. This was, at a point in the history of humankind, Walter's opinion of a good starting point for talking about const: true ROMable values. However, that approach is too rigid to be useful: too rarely you have truly immutable data, but most often you want to make sure that certain parts of a system *think* data is immutable.

Let's talk about references for a bit first. You have "normal" (mutable) references and const references. When you create an object, you get a mutable reference by default, or a const reference if you ask for it ("new const C"). Normal references implicitly convert to const references, but not the other way around.

I just figured that an object created by "new const" would be a "const object", since no non-const references to it are possible without invoking undefined behavior (e.g. using pointer casts). Therefore it can't be modified.

> A relaxation of that concept therefore is to associate constness with the reference through which the value is accessed. Then you have much more flexibility in that you can have some mutable object, pass it to a function through a const handle (thus knowing that that function can never change it), and then continue enjoying mutable access to that object.
> 
> The downside of this relaxation is that aliasing might stick its nose. My conjecture is that in the vast majority of cases it can be trivially proved (by the compiler) that no aliased access can affect const data. And even in the cases where the compiler must generates conservative code (as it does today in 100% of the cases), the benefit to the programmer still justifies this more relaxed view of immutability.

For D, you may be right because of the way modules work; the compiler will often have the source to all functions called.
For C++ that conjecture will often be wrong, simply because the implementation of functions called will often be in a source file the compiler can't see (it has only seen the header).

The compiler needs to either see every variable accessible from called functions (to make sure they can't contain or (transitively) reference an alias) or know for certain that no mutable references accessible to called functions exist (because it sees the allocation and the implementation of every function it may have been mutably passed to).
Or maybe there's another way to be sure it won't be modified that I didn't think of, but I don't think there's any way to be sure if it's ever been a mutable parameter to an unseen function and another unseen function is then called.

> So: class objects are never const. Const references only restrict access, not the nature of bits on the heap.

I didn't mean "const object" to mean anything about the nature of the bits, I just used the term to indicate an object that has been const since allocation because it was allocated with "new const".
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Frits van Bommel wrote:
>> Andrei Alexandrescu (See Website For Email) wrote:
>>> Frits van Bommel wrote:
>>>> But as I mentioned, there will only be const references to const instances, so that would mean const objects couldn't be explicitly deleted.
>>>> And there are people who prefer or need to work with GC off. This limitation would deny them the use of const objects (unless they like memory leaks ;) ).
>>>
>>> I disagree. If you want to disable the GC, that doesn't mean you can't use const. You use a private non-const reference for ownership purposes, and you use a const reference for publishing purposes:
>>
>> <pedantic> I said const *objects*, not const references. </pedantic>
> 
> This is actually a great point. In the case of classes, is const a property of the value, or a property of the reference through which the value is accessed?
> 
> This philosophical-sounding question leads actually to radically different implementations. If you associate constness with the value, then you have true immutable values. This was, at a point in the history of humankind, Walter's opinion of a good starting point for talking about const: true ROMable values. However, that approach is too rigid to be useful: too rarely you have truly immutable data, but most often you want to make sure that certain parts of a system *think* data is immutable.
> 
> A relaxation of that concept therefore is to associate constness with the reference through which the value is accessed. Then you have much more flexibility in that you can have some mutable object, pass it to a function through a const handle (thus knowing that that function can never change it), and then continue enjoying mutable access to that object.
> 
> The downside of this relaxation is that aliasing might stick its nose. My conjecture is that in the vast majority of cases it can be trivially proved (by the compiler) that no aliased access can affect const data. And even in the cases where the compiler must generates conservative code (as it does today in 100% of the cases), the benefit to the programmer still justifies this more relaxed view of immutability.
> 
> So: class objects are never const. Const references only restrict access, not the nature of bits on the heap.
> 
> 
> Andrei

So then I ask, why have const constructors/destructors?  What, given an (even contrived) example, would be the likely difference in code between constant and non-constant constructors/destructors?  And how is this:
# Foo f = new const Foo;

Different from this:
# const Foo f = new Foo;

Granted I like the direction D is headed with const if this is indicative, I'm just stuck on a few points.  Probably won't be able to form a full opinion until I can see it in action.

-- Chris Nicholson-Sauls
January 23, 2007
Frits van Bommel wrote:
> Let's talk about references for a bit first. You have "normal" (mutable) references and const references.

Yah.

> When you create an object, you get a mutable reference by default, or a const reference if you ask for it ("new const C"). Normal references implicitly convert to const references, but not the other way around.

Yah.

> I just figured that an object created by "new const" would be a "const object", since no non-const references to it are possible without invoking undefined behavior (e.g. using pointer casts). Therefore it can't be modified.

In D, an object created with "new const" is exactly like the proverbial tree falling in the forest: it's actually not const, but nobody can change it, so nobody can tell.

>> The downside of this relaxation is that aliasing might stick its nose. My conjecture is that in the vast majority of cases it can be trivially proved (by the compiler) that no aliased access can affect const data. And even in the cases where the compiler must generates conservative code (as it does today in 100% of the cases), the benefit to the programmer still justifies this more relaxed view of immutability.
> 
> For D, you may be right because of the way modules work; the compiler will often have the source to all functions called.
> For C++ that conjecture will often be wrong, simply because the implementation of functions called will often be in a source file the compiler can't see (it has only seen the header).
> 
> The compiler needs to either see every variable accessible from called functions (to make sure they can't contain or (transitively) reference an alias) or know for certain that no mutable references accessible to called functions exist (because it sees the allocation and the implementation of every function it may have been mutably passed to).
> Or maybe there's another way to be sure it won't be modified that I didn't think of, but I don't think there's any way to be sure if it's ever been a mutable parameter to an unseen function and another unseen function is then called.

Something like that. Don't forget, however, that exceedingly few optimizations make assumptions across a function call. In the most frequent case, you just want to make sure that some data is immutable over a short burst of primitive operations. I think this is easily doable.


Andrei
January 23, 2007
Chris Nicholson-Sauls wrote:
> So then I ask, why have const constructors/destructors?  What, given an (even contrived) example, would be the likely difference in code between constant and non-constant constructors/destructors?  And how is this:

A constructor might take different decisions on caching, preallocating
etc. when it prepares for mutability, as opposed to it knowing that the
object won't change. For example, creating a const deque might cause a different allocation strategy than a non-const one.

> # Foo f = new const Foo;
> 
> Different from this: # const Foo f = new Foo;

In the latter case you are robbing the constructor from a little piece of information. Things will still work.


Andrei
January 23, 2007
Andrei Alexandrescu (See Website For Email) wrote:
> Chris Nicholson-Sauls wrote:
>> So then I ask, why have const constructors/destructors?  What, given an (even contrived) example, would be the likely difference in code between constant and non-constant constructors/destructors?  And how is this:
> 
> A constructor might take different decisions on caching, preallocating
> etc. when it prepares for mutability, as opposed to it knowing that the
> object won't change. For example, creating a const deque might cause a different allocation strategy than a non-const one.

Okay, granted.  (Const instances coming from a pool rather than newly created, for example.)  So, a new question, can the const constructors call the "normal" constructors?  Aka:

class Foo {
  this () { /* ... do stuff ... */ }

  this(const) () {
    // ... yadda yadda
    this();
    // ... yadda yadda
  }
}

And what else might possible gain this odd 'func(attr)(...)' notation later?  Its... interesting, to be sure.  But certainly better to my eyes than 'func (...) const' and company ever were.

>> # Foo f = new const Foo;
>>
>> Different from this: # const Foo f = new Foo;
> 
> In the latter case you are robbing the constructor from a little piece of information. Things will still work.
> 
> 
> Andrei

Actually this was inadvertantly answered for me when I read elsewhere in the thread of the notion of const playing a part in implicit casting, namely that mutable->const is valid while const->mutable is not.  Just had a dull brain moment, I suppose.  :)

-- Chris Nicholson-Sauls
January 24, 2007
Chris Nicholson-Sauls wrote:
> Andrei Alexandrescu (See Website For Email) wrote:
>> Chris Nicholson-Sauls wrote:
>>> So then I ask, why have const constructors/destructors?  What, given an (even contrived) example, would be the likely difference in code between constant and non-constant constructors/destructors?  And how is this:
>>
>> A constructor might take different decisions on caching, preallocating
>> etc. when it prepares for mutability, as opposed to it knowing that the
>> object won't change. For example, creating a const deque might cause a different allocation strategy than a non-const one.
> 
> Okay, granted.  (Const instances coming from a pool rather than newly created, for example.)  So, a new question, can the const constructors call the "normal" constructors?  Aka:
> 
> class Foo {
>   this () { /* ... do stuff ... */ }
> 
>   this(const) () {
>     // ... yadda yadda
>     this();
>     // ... yadda yadda
>   }
> }

Yes. Also, it should be notice that a const constructor could escape a non-const reference to this, which makes the tree falling in the forest audible. This is in keep with the intended semantics of const, and testament to the fact that you don't want a more restrictive semantics.

> And what else might possible gain this odd 'func(attr)(...)' notation later?  Its... interesting, to be sure.  But certainly better to my eyes than 'func (...) const' and company ever were.

Scope is another interesting attribute that you may want to detect.


Andrei