November 15, 2021

On Monday, 15 November 2021 at 08:38:07 UTC, Ola Fosheim Grøstad wrote:

>

The reason you can cast away const is so that you can call C-APIs that actually have const-behaviour, but not a const signature.

Also note that objects that are created as const should not be modified, quoting cppreference:

«const object - an object whose type is const-qualified, or a non-mutable subobject of a const object. Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.»

November 15, 2021

On Monday, 15 November 2021 at 08:38:07 UTC, Ola Fosheim Grøstad wrote:

>

On Monday, 15 November 2021 at 07:14:12 UTC, Walter Bright wrote:

>

On 11/14/2021 12:04 PM, H. S. Teoh wrote:

>

Given D's emphasis on generic code, (1) seems like the only viable
option. Which makes const in D even narrower in scope than ever.

C++ const doesn't actually work, which is why C++ ref counted objects can be const.

Uh? C++ shared_ptr stores the count in a separate object.

The reason you can cast away const is so that you can call C-APIs that actually have const-behaviour, but not a const signature.

You have to be able to do this in D to.

I think he meant from optimisation viewpoint. C++ const is so weak that it can't be used for actual optimisations anyway, at least usually. So no performance is lost because of mutable. In D the compiler can make some assumption based on const and immutable, so we lose some performance potential if we implement mutable.

November 15, 2021
rather than punching a hole in const/immutable

struct S
meta {
int refCount;
....
}
do {
 int payload;
....
}

Immutable S s is now conceptually an immutable object and a mutable
object with metadata behind the scenes
that feels like a single object from a user perspective?
November 15, 2021

On Monday, 15 November 2021 at 09:22:16 UTC, Dukc wrote:

>

I think he meant from optimisation viewpoint. C++ const is so weak that it can't be used for actual optimisations anyway, at least usually.

You cannot assume a lot about the underlying C++ object that is accessed through a reference, that is true. But you can infer the constness of functions by static analysis.

The most critical const objects are lookup-tables and one should be able to establish those as immutable in C++ too, as they are const objects that are not accessed through a "remote" pointer.

>

So no performance is lost because of mutable. In D the compiler can make some assumption based on const and immutable, so we lose some performance potential if we implement mutable.

Maybe, although it is kinda the same as having a mutable object with mostly immutable fields.

So, I would think that could be covered by having a mechanism for inferring "full immutability"?

November 15, 2021
On 15/11/2021 10:28 PM, Danni Coy wrote:
> that feels like a single object from a user perspective?

The most important thing about this is: it'll all be in continuous memory.

Perfect for all of your crashing needs due to read only memory!
November 15, 2021
On Monday, 15 November 2021 at 09:28:41 UTC, Danni Coy wrote:
> rather than punching a hole in const/immutable
>
> struct S
> meta {
> int refCount;
> ....
> }
> do {
>  int payload;
> ....
> }
>
> Immutable S s is now conceptually an immutable object and a mutable
> object with metadata behind the scenes
> that feels like a single object from a user perspective?

That is functionally the same thing as '__mutable int refCount', discussed elsethread.
November 15, 2021
On Mon, Nov 15, 2021 at 9:50 PM Elronnd via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
>
> On Monday, 15 November 2021 at 09:28:41 UTC, Danni Coy wrote:
> > rather than punching a hole in const/immutable
> >
> > struct S
> > meta {
> > int refCount;
> > ....
> > }
> > do {
> >  int payload;
> > ....
> > }
> >
> > Immutable S s is now conceptually an immutable object and a
> > mutable
> > object with metadata behind the scenes
> > that feels like a single object from a user perspective?
>
> That is functionally the same thing as '__mutable int refCount', discussed elsethread.

>From an implementation point of view maybe. It has the advantage of
having the linguistic model match what the compiler is doing behind the scenes (making it easier to reason about / conceptualise).

Would it be possible to limit operation of the writeable components to a small subset of the language which would allow the necessary operations but remove a lot of the complications?
November 15, 2021

On Monday, 15 November 2021 at 09:22:16 UTC, Dukc wrote:

>

I think he meant from optimisation viewpoint. C++ const is so weak that it can't be used for actual optimisations anyway, at least usually. So no performance is lost because of mutable. In D the compiler can make some assumption based on const and immutable, so we lose some performance potential if we implement mutable.

You can only optimize based on immutable and even then you need to run data-flow analysis to figure out whether someone could do any casts which make the optimization invalid.

And const doesn't provide any additional grantees an optimizer could use directly.
It's a feature to prevent misuse of an API only.

I have personal experience which show that as soon as multiple threads involved const does more harm than good because it only allows you to reason about your access rights you cannot infer anything about anyone else.

November 15, 2021
On 15.11.21 11:36, rikki cattermole wrote:
> 
> On 15/11/2021 10:28 PM, Danni Coy wrote:
>> that feels like a single object from a user perspective?
> 
> The most important thing about this is: it'll all be in continuous memory.
> 
> Perfect for all of your crashing needs due to read only memory!

Whoever allocates the object knows the memory layout and can put it in writable memory.
November 15, 2021
On 15.11.21 08:05, Walter Bright wrote:
> On 11/14/2021 1:12 PM, Steven Schveighoffer wrote:
>> First, I'll note that `__mutable` on its own is perfectly sound.
> 
> I don't think so. It produces two kinds of immutability - one with mutable members, one with not. Different rules apply.
> 
> But then what do you do with opaque types? The compiler doesn't know which kind of immutable they are. So it is forced to go with the worst case - immutables are mutable. And it all falls apart.
> 

My answer to this was nondeterministic semantics. Just say what all the rewrites are that the compiler is allowed to do. Then @trusted __mutable functions have to ensure they function correctly _even if_ optimizations change the specific __mutable function calls and their arguments.

Another example of nondeterministic semantics is implicit moving. The compiler can either move directly or just copy construct and destroy. Then, the type itself has to ensure it does not matter for overall correctness which specific set of operations is applied even if they do not result in exactly the same bit patterns. This works and similar nondeterministic semantics can be made to work for __mutable data.

Of course, this is more technically involved than just saying "`immutable` means immutable" (a rare feat for D keywords), but you still have to address the issue of deallocation anyway.