November 15, 2015
On 11/15/2015 01:50 PM, Jonathan M Davis wrote:
> On Sunday, 15 November 2015 at 18:09:15 UTC, Andrei Alexandrescu wrote:
>> On 11/15/2015 01:00 PM, Jonathan M Davis wrote:
>>> Basically, we have to decide between having physical const with the
>>> guarantees that it provides
>>
>> We have that - it's immutable. -- Andrei
>
> Yes and no. As it stands, I can know that
>
> const foo = getFoo();
> foo.bar();
>
> won't mutate foo unless I have another, mutable reference to foo
> somewhere that bar somehow accessed.

That is an illusion, and we need to internalize that. Consider:

// inside some module
struct T
{
  int[] data;
  void bar()
  {
    // look, ma, no hands
    g_data[1]++;
  }
}
static int[] g_data;
const(T) getFoo()
{
  T result;
  result.data = g_data = [1, 2, 3];
  return result;
}

In other words, you truly need access to the implementation of getFoo() in order to claim anything about the changeability of stuff. Note that I could even afford to have getFoo() return const, so no need for the caller to make it so!

With immutable, it's all cool. Immutable data is truly immutable, and that can be counted on. But const, even today, cannot be assumed to be as strong.


Andrei
November 15, 2015
On Sunday, 15 November 2015 at 19:51:09 UTC, Andrei Alexandrescu wrote:
> Just to clarify - is that referring to the part "We need to change that if we want things like composable containers that work with const." or to the "I think it's a good thing to want" part? -- Andrei

Second part. I don't see a case for const containers at all. Fully immutable functional style ones - sure, I have actually experimented implementing cache this way in https://github.com/Dicebot/mood/blob/master/source/mood/storage/generic_cache.d (thing that powers blog.dicebot.lv). But what would you use const containers for? Mixing mutable and immutable elements in one container? That sounds like a source of much trouble.
November 15, 2015
On 11/15/2015 08:57 PM, Andrei Alexandrescu wrote:
> On 11/15/2015 01:50 PM, Jonathan M Davis wrote:
>> On Sunday, 15 November 2015 at 18:09:15 UTC, Andrei Alexandrescu wrote:
>>> On 11/15/2015 01:00 PM, Jonathan M Davis wrote:
>>>> Basically, we have to decide between having physical const with the
>>>> guarantees that it provides
>>>
>>> We have that - it's immutable. -- Andrei
>>
>> Yes and no. As it stands, I can know that
>>
>> const foo = getFoo();
>> foo.bar();
>>
>> won't mutate foo unless I have another, mutable reference to foo
>> somewhere that bar somehow accessed.
>
> That is an illusion, and we need to internalize that. Consider:
>
> // inside some module
> struct T
> {
>    int[] data;
>    void bar()
>    {
>      // look, ma, no hands
>      g_data[1]++;
>    }
> }
> static int[] g_data;
> const(T) getFoo()
> {
>    T result;
>    result.data = g_data = [1, 2, 3];
>    return result;
> }
> ...


This is the exact exception he described i.e. "unless I have another, mutable reference to foo somewhere that bar somehow accessed."

(Also, 'bar' should be 'const'.)

> In other words, you truly need access to the implementation of getFoo()
> in order to claim anything about the changeability of stuff.

No, e.g., make either 'getFoo' or 'bar' pure.

> Note that I
> could even afford to have getFoo() return const, so no need for the
> caller to make it so!
>
> With immutable, it's all cool. Immutable data is truly immutable, and
> that can be counted on. But const, even today, cannot be assumed to be
> as strong.
> ...

This is obviously true (it is what justifies the distinction between const and immutable in the first place), but this is not a way to justify making it weaker. This is all just moving in the direction of a setting where all structs/classes just prevent immutable construction and make all member functions const, and const becomes the new mutable. I don't see the point.
November 15, 2015
On Friday, 13 November 2015 at 23:10:04 UTC, Andrei Alexandrescu wrote:
> I created a simple persistent list with reference counting and custom allocation at http://dpaste.dzfl.pl/0981640c2835.


There is also another thing I wanted to mention on topic of persistent containers. Right now for me the most intriguing topic is trying to define immutable (and actually thread shared) cache data structure than can be efficiently and safely used without GC. There is whole class of tasks where you can get best performance by building new copy of cache in memory instead of modifying separate elements, trading increased memory concsumption for fast no lock parallel access. However in absence of GC task of deleting memory for older generations of cache becomes rather challenging. I have been thinking about approach with external two-level reference counting + dedicated allocator - quick thread-local RC comes first and once it goes to 0, shared RC in allocator gets decremented (being effetively user thread counter). Do you think it can work?
November 15, 2015
On 11/15/2015 03:11 PM, Dicebot wrote:
> On Sunday, 15 November 2015 at 19:51:09 UTC, Andrei Alexandrescu wrote:
>> Just to clarify - is that referring to the part "We need to change
>> that if we want things like composable containers that work with
>> const." or to the "I think it's a good thing to want" part? -- Andrei
>
> Second part. I don't see a case for const containers at all. Fully
> immutable functional style ones - sure, I have actually experimented
> implementing cache this way in
> https://github.com/Dicebot/mood/blob/master/source/mood/storage/generic_cache.d
> (thing that powers blog.dicebot.lv). But what would you use const
> containers for?

Passing arguments to functions that aren't supposed to change the containers. -- Andrei


November 15, 2015
On 11/15/2015 03:17 PM, Timon Gehr wrote:
> On 11/15/2015 08:57 PM, Andrei Alexandrescu wrote:
>> On 11/15/2015 01:50 PM, Jonathan M Davis wrote:
>>> On Sunday, 15 November 2015 at 18:09:15 UTC, Andrei Alexandrescu wrote:
>>>> On 11/15/2015 01:00 PM, Jonathan M Davis wrote:
>>>>> Basically, we have to decide between having physical const with the
>>>>> guarantees that it provides
>>>>
>>>> We have that - it's immutable. -- Andrei
>>>
>>> Yes and no. As it stands, I can know that
>>>
>>> const foo = getFoo();
>>> foo.bar();
>>>
>>> won't mutate foo unless I have another, mutable reference to foo
>>> somewhere that bar somehow accessed.
>>
>> That is an illusion, and we need to internalize that. Consider:
>>
>> // inside some module
>> struct T
>> {
>>    int[] data;
>>    void bar()
>>    {
>>      // look, ma, no hands
>>      g_data[1]++;
>>    }
>> }
>> static int[] g_data;
>> const(T) getFoo()
>> {
>>    T result;
>>    result.data = g_data = [1, 2, 3];
>>    return result;
>> }
>> ...
>
>
> This is the exact exception he described i.e. "unless I have another,
> mutable reference to foo somewhere that bar somehow accessed."

Nope. He doesn't have a reference; the implementation has surreptitiously, without the caller's knowledge.

Big difference! That means the modular typechecker cannot make any assumption about the immutability of that object.

Let me repeat: const is already as weak as some fear it might be. (Immutable is fine.)

> (Also, 'bar' should be 'const'.)

Right.

>> In other words, you truly need access to the implementation of getFoo()
>> in order to claim anything about the changeability of stuff.
>
> No, e.g., make either 'getFoo' or 'bar' pure.

Well but it's not. Keep the goalposts where they are. This is about "const". I do agree that "pure const" may have other, stronger properties. But let's discuss "const" and what it can promise, or move over to a whole new topic of "pure const".

>> Note that I
>> could even afford to have getFoo() return const, so no need for the
>> caller to make it so!
>>
>> With immutable, it's all cool. Immutable data is truly immutable, and
>> that can be counted on. But const, even today, cannot be assumed to be
>> as strong.
>> ...
>
> This is obviously true (it is what justifies the distinction between
> const and immutable in the first place), but this is not a way to
> justify making it weaker.

Weaker than what? I've just shown black on white it's not a guarantee of constant data. Today. With no compiler bugs in sight.

> This is all just moving in the direction of a
> setting where all structs/classes just prevent immutable construction
> and make all member functions const, and const becomes the new mutable.
> I don't see the point.

I don't understand this.


Andrei

November 15, 2015
On 11/15/2015 03:23 PM, Dicebot wrote:
> On Friday, 13 November 2015 at 23:10:04 UTC, Andrei Alexandrescu wrote:
>> I created a simple persistent list with reference counting and custom
>> allocation at http://dpaste.dzfl.pl/0981640c2835.
>
>
> There is also another thing I wanted to mention on topic of persistent
> containers. Right now for me the most intriguing topic is trying to
> define immutable (and actually thread shared) cache data structure than
> can be efficiently and safely used without GC. There is whole class of
> tasks where you can get best performance by building new copy of cache
> in memory instead of modifying separate elements, trading increased
> memory concsumption for fast no lock parallel access. However in absence
> of GC task of deleting memory for older generations of cache becomes
> rather challenging. I have been thinking about approach with external
> two-level reference counting + dedicated allocator - quick thread-local
> RC comes first and once it goes to 0, shared RC in allocator gets
> decremented (being effetively user thread counter). Do you think it can
> work?

I don't think we can make that work with current language semantics. I'll post more about that soonish. -- Andrei
November 15, 2015
On Sunday, 15 November 2015 at 21:00:40 UTC, Andrei Alexandrescu wrote:
> On 11/15/2015 03:11 PM, Dicebot wrote:
>> Second part. I don't see a case for const containers at all. Fully
>> immutable functional style ones - sure, I have actually experimented
>> implementing cache this way in
>> https://github.com/Dicebot/mood/blob/master/source/mood/storage/generic_cache.d
>> (thing that powers blog.dicebot.lv). But what would you use const
>> containers for?
>
> Passing arguments to functions that aren't supposed to change the containers. -- Andrei

For that you don't need to mutate neither allocator nor RC (unless that const argument is actually leaked from inside the function to somewhere else - terrible, terrible thing to do). So strict physical const should suffice.
November 16, 2015
On 11/15/2015 04:45 PM, Dicebot wrote:
> On Sunday, 15 November 2015 at 21:00:40 UTC, Andrei Alexandrescu wrote:
>> On 11/15/2015 03:11 PM, Dicebot wrote:
>>> Second part. I don't see a case for const containers at all. Fully
>>> immutable functional style ones - sure, I have actually experimented
>>> implementing cache this way in
>>> https://github.com/Dicebot/mood/blob/master/source/mood/storage/generic_cache.d
>>>
>>> (thing that powers blog.dicebot.lv). But what would you use const
>>> containers for?
>>
>> Passing arguments to functions that aren't supposed to change the
>> containers. -- Andrei
>
> For that you don't need to mutate neither allocator nor RC (unless that
> const argument is actually leaked from inside the function to somewhere
> else - terrible, terrible thing to do). So strict physical const should
> suffice.

This illustrates a simple procedural problem. The entire point of my posting a simple example of a complete container was to avoid hypotheticals such as this. The code is there and shows that no, physical const does not suffice. At least I don't know how to do it. If you think it does there's one way to show it, it's easy - write the code that does it.

We could sit on our testes all day long, speculate how things ought to work, and feel awfully smart in the process. It's very easy to do. Hell, I've done it more than too many times. What's more difficult is have a positive, constructive approach that builds on a weak solution to improve it. This is the kind of dialog we need to foster.


Andrei

November 16, 2015
On 11/15/2015 10:06 PM, Andrei Alexandrescu wrote:
> ...
> I do agree that "pure const" may have other, stronger
> properties.  But let's discuss "const" and what it can promise, or move
> over to a whole new topic of "pure const".
> ...

"pure" is independent of "const" at the moment. So what you want to discuss is "const" in impure method signatures. Fine.

In any case, consider that you might at some point be asked to explain why a const List is a good thing to want but a const pure List isn't.

>>> Note that I
>>> could even afford to have getFoo() return const, so no need for the
>>> caller to make it so!
>>>
>>> With immutable, it's all cool. Immutable data is truly immutable, and
>>> that can be counted on. But const, even today, cannot be assumed to be
>>> as strong.
>>> ...
>>
>> This is obviously true (it is what justifies the distinction between
>> const and immutable in the first place), but this is not a way to
>> justify making it weaker.
>
> Weaker than what? I've just shown black on white it's not a guarantee of
> constant data.

In one particular case.

import package.module : foo, bar, baz, fun;

final class C{
    int x;
    private this(int x){ this.x=x; }
}

void main(){
    auto c = new C(2);
    foo(c); // void foo(const C c);
    bar();  // impure
    baz();  // impure
    fun(c.x); // this read of c.x can be optimized away under current semantics, not under the new ones
}


> Today. With no compiler bugs in sight.
> ...

Do you mean, even ignoring compiler bugs?

>> This is all just moving in the direction of a
>> setting where all structs/classes just prevent immutable construction
>> and make all member functions const, and const becomes the new mutable.
>> I don't see the point.
>
> I don't understand this.
>...

const is transitive and contagious. Make casting away const legal and spuriously require const in some places in the library, and you will have created a quite large incentive to use the now legal casts in a way that some will consider unprincipled.