November 16, 2015
On Monday, 16 November 2015 at 02:26:29 UTC, Andrei Alexandrescu wrote:
> Yah, I agree with that argument. Probably @mutable is a more principled way to go about things.

Glad to here that. I think the current transitive const system is really good and shouldn't be watered down beyond necessity. And a @mutable keyword, too, shouldn't just mean "immutability or const-ness end here", thus allowing any kind of mutation. What we actually need for immutable/const refcounting etc. is _non-observable mutation_, i.e. physical mutability, but without observable effects outside of the type's implementation (better yet, restricted to very short parts of it, just like @trusted).
November 16, 2015
On Monday, 16 November 2015 at 09:42:43 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 16 November 2015 at 09:04:33 UTC, Joseph Cassman wrote:
>> [...]
>
> The D designers might want to look at Pony lang's capability system, which has been proven sound. It has 6 different aliasing capabilites that regulates among other things transition from mutable to immutable.
>
> D is a little bit better of (if it does not allow casting away const) than C++, because in C++ const is essentially "shared const", whereas in D in is "local const with potential aliasing". AFAIK the D sementics is that no other thread can hold a mutable reference to something you have as const. But it is still a relatively weak guarantee. In C you have "restricted" for notifying the compiler that the resource is aliasing free within the context.

You described immutable, not const. If one thread has a const reference, it's entirely possible another thread has a mutable reference.

Atila
November 16, 2015
On 11/16/2015 08:51 AM, Marc Schütz wrote:
> On Monday, 16 November 2015 at 02:26:29 UTC, Andrei Alexandrescu wrote:
>> Yah, I agree with that argument. Probably @mutable is a more
>> principled way to go about things.
>
> Glad to here that. I think the current transitive const system is really
> good and shouldn't be watered down beyond necessity. And a @mutable
> keyword, too, shouldn't just mean "immutability or const-ness end here",
> thus allowing any kind of mutation. What we actually need for
> immutable/const refcounting etc. is _non-observable mutation_, i.e.
> physical mutability, but without observable effects outside of the
> type's implementation (better yet, restricted to very short parts of it,
> just like @trusted).

The challenge is proving that a mutation is not observable. Got an attack on that? -- Andrei
November 16, 2015
On Monday, 16 November 2015 at 14:08:23 UTC, Atila Neves wrote:
> You described immutable, not const. If one thread has a const reference, it's entirely possible another thread has a mutable reference.

Only if it's shared, or you've screwed up with casting and ended up with an object which is actually shared being treated as TLS. A const, non-shared object can't possibly be mutated while you're doing stuff to it unless that same code somehow has access to a mutable reference to the same data. And in most cases (particularly if you're using pure heavily), it won't have access to any other references to the same data, so you can usually rely on a const object not being mutated while you operate on it.

- Jonathan M Davis
November 16, 2015
On Monday, 16 November 2015 at 14:45:35 UTC, Andrei Alexandrescu wrote:
> On 11/16/2015 08:51 AM, Marc Schütz wrote:
>> On Monday, 16 November 2015 at 02:26:29 UTC, Andrei Alexandrescu wrote:
>>> Yah, I agree with that argument. Probably @mutable is a more
>>> principled way to go about things.
>>
>> Glad to here that. I think the current transitive const system is really
>> good and shouldn't be watered down beyond necessity. And a @mutable
>> keyword, too, shouldn't just mean "immutability or const-ness end here",
>> thus allowing any kind of mutation. What we actually need for
>> immutable/const refcounting etc. is _non-observable mutation_, i.e.
>> physical mutability, but without observable effects outside of the
>> type's implementation (better yet, restricted to very short parts of it,
>> just like @trusted).
>
> The challenge is proving that a mutation is not observable. Got an attack on that? -- Andrei

That would be a neat trick. As I recall, previous discussions on logical const concluded that there was no way to implement it in a way that guaranteed that it was actually logical const as opposed to just being mutated in spite of being const. But it would be _very_ cool if someone figured out how to do it.

Still, even without that guarantee, using something like @mutable rather than casting would be far safer - especially if the type system can guarantee that such an object can't be immutable.

- Jonathan M Davis
November 16, 2015
On Monday, 16 November 2015 at 14:08:23 UTC, Atila Neves wrote:
> You described immutable, not const. If one thread has a const reference, it's entirely possible another thread has a mutable reference.

Are you sure that this is a well defined situation? What is the point of having "const" if "shared const" is the exact same thing?

Immutable should never ever change for any reason, because the compiler should be able to cache derived values.

November 16, 2015
On Monday, 16 November 2015 at 08:18:55 UTC, Jonathan M Davis wrote:
> And actually, this gives me an interesting thought. Does making casting away const and mutating defined behavior give us a way to fix our postblit problem? I could see an argument that postblits should be completely unnecessary for immutable values (because you shouldn't need to avoid stuff like sharing references when it's immutable), which could mean that we could change it so that immutable structs values didn't trigger a postblit and thus worked fine as-is, and that would fix the problem with postblits and immutable. And if casting away const and mutating is legit, then it should be possible to treat the struct itself as mutable (or at least tail-const) within the postblit constructor, in which case it's then actually possible to have postblit constructor that works with const, whereas right now, we can't have it, because it would violate const to mutate the newly blitted, const struct.
>
> So, if this really fixes our postblit problem, it might be worth it just for that. As it stands, postblit constuctors tend to have to be avoided in many cases because of how badly they interact with const and immutable.

Actually, with regards to immutable, it looks like you can already copy immutable objects with postblit constructors. You just can't copy it and get a mutable value out of it. But copying and creating another immutable value or a const value both work just fine. So, it looks like the only thing we're missing with regards to immutable and postblits is the ability to get a mutable copy, but that's not really much of a loss as far as I can think of at the moment.

So, really it's just the issue with const and postblit that really needs fixing, and allowing the mutation of const to be defined behavior when the underlying object isn't immutable could give us the out we need to fix that problem.

- Jonathan M Davis
November 16, 2015
On 11/14/15 10:44 AM, Andrei Alexandrescu wrote:

> That doesn't work for me with my unittests, I get:


I'm such an idiot, I depended on dpaste to run the unit test, but forgot to check the unit test button.

So technically, my updated version *parses* correctly :)

Looking in more depth...

-Steve

November 16, 2015
On 11/14/15 3:42 AM, Dmitry Olshansky wrote:
> On 14-Nov-2015 02:10, Andrei Alexandrescu wrote:

>> * Lines 141-152: I couldn't make tail() work with inout. Generally I'm
>> very unhappy about inout. I don't know how to use it. Everything I read
>> about it is extremely complicated compared to its power. I wish we
>> removed it from the language and replaced it with an understandable
>> idiom.
>>
>
> I can't agree more. Every time dealing with inout when I finally think I
> grok how it works the next instant I see that it doesn't do what I expect.
>
> For me inout inevitably stops at the boundary of being unnable to have
> List!(inout(T)) and the like.

One thing we could allow is types that contain inout member variables, but ONLY in the context of inout functions. In other words, you can create a type for it, but can only use it in the context of an inout function.

A List!(inout(T)) outside an inout function has no meaning. This is why we disallowed it.

However, my belief is that it's the lack of a mechanism to apply an attribute to the tail of some struct that prevents the most utility here. If you returned a List!(inout(T)) there is no way to magically convert it to a List!(const(T)) or List!(immutable(T)).

Consider that Node in this code has a "const(Node)* next" as its tail.

I believe we should be able to achieve both.

-Steve
November 16, 2015
On 16/11/15 22:45, Andrei Alexandrescu wrote:
> On 11/16/2015 08:51 AM, Marc Schütz wrote:
>> On Monday, 16 November 2015 at 02:26:29 UTC, Andrei Alexandrescu wrote:
>>> Yah, I agree with that argument. Probably @mutable is a more
>>> principled way to go about things.
>>
>> Glad to here that. I think the current transitive const system is really
>> good and shouldn't be watered down beyond necessity. And a @mutable
>> keyword, too, shouldn't just mean "immutability or const-ness end here",
>> thus allowing any kind of mutation. What we actually need for
>> immutable/const refcounting etc. is _non-observable mutation_, i.e.
>> physical mutability, but without observable effects outside of the
>> type's implementation (better yet, restricted to very short parts of it,
>> just like @trusted).
>
> The challenge is proving that a mutation is not observable. Got an
> attack on that? -- Andrei

Forgive me, I haven't followed the RC discussions closely, so I miss a lot of context. Feel free to point me to existing threads/articles.

If it's RC we want, then @mutable is an axe when what we need is a scalpel.

The non-observability comes from the fact the refcount is changed when the caller has lost its (const) reference and constness is a moot point. Changing refcount is fine now, provided the object is not immutable. As far as other outstanding const references go, these already expect changes to happen.

This is what makes refcount special and provably safe to mutate. As long as we can ensure the object is not immutable, the object is allowed to change its own refcount. But refcount needs to be special cased, somehow, or else we'll end up with some C++ like `mutable`.

Perhaps const-but-not-pure is the solution here. The object must be able to store (and have stored) a mutable reference, so it can use that reference to change the refcount. (This could be optimized to be a flag, since the mutable and const reference would refer to the same instance.) It means keeping track of const-but-mutable vs const-and-immutable references, and somehow telling the compiler that refcount is special.

L.