November 15, 2021
On Monday, 15 November 2021 at 11:40:45 UTC, Danni Coy wrote:
> 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?

Yes using special case in the compiler, special case in the type system.
(looks like "meta" is a bit like "__mutable", which's been discussed previously).

In the domain of special cases I'd prefer a built-in reference counted
"type next", e.g like `[]` `*`, that says rather than an attribute created _just to have the library solution to work_.




November 15, 2021

On Monday, 15 November 2021 at 09:42:03 UTC, Ola Fosheim Grøstad wrote:

>

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"?

Would a new keyword be required or would it be enough to specify it so that optimizations could be done etc? (So that we don't loose the "benefits" we have today). Sorry, I'm writing this the fly so haven't thought this through.

For me the right solution though seems to be keeping it "external".

Why? Don't touch the object, the usage of it is not of it's concern.

If we view it as a canonical object like the number 7, we don't keep track in the object itself where it's used. When we bring it from the platonic to the physical world by "instantiating" it as a copy. If you destroy our copy, the canonical (eternal) object doesn't change.

Hence, it makes more sense to keep track of it in a separately, maybe even in another universe (depending on interpretation).

You can view it as what's happening is something like you get a copy of the entire universe with one bit changed, let's say a count variable x (I'm only using natural numbers here). The canonical values lives outside the omniverse.

In this example a universe can bind a canonical value to a variable and observe the value of a variable. I have also thrown in the successor function (suc(n) = n+1) and predecessor function (pre(n+1) = n) because why not (this is pseudo for the sake of discussion)

Universe u0 = Omniverse.getUniverse(0); //You reference a universe by a natural number or view it as a new Universe() where the omniverse sets the "blueprint", this boils down to the interpretation

// Bind 7 to x, it just means that the (canonical value from the platonic domain) of 7 is stored within the universe as a (imperfect or perfect (hopefully)) representation (data)
u0.bind(x, 7);

// What's happening here is another canonical value is being bound and put into x (yes I know)
u0.bind(x, suc(u0.observe(x))); //This is (if the observation is not corrupted etc) equivalent with u0.bind(x, 8)

// A new universe would get x = 8 here
Universe u1 = u0; // Create a new universe by copying an old one from the omniverse (or not, depending on your interpretation, I don't have time to write both atm)

u1.bind(x, pre(u1.observe(x))); // Bind x in this universe to the predecessor of x
u1.observe(x); // Would observe 7

// The philosophical discussions begin here...

// Should/can u1 be able to observe something in u0, if so, how?
// What makes the omniverse consistent?
// etc etc, not so interested in this atm :)

So the hierarchy would be
Platonic -> Omniverse -> Universe -> Data -> Information (interpreted data)

The destruction (removal), mutation (intentional change) or corruption (unintentional change) of a variable does not in any way make its way up the hierarchy by other than explicit copy (using that interpretation), it's contained within the universe or can only move horizontally.

How does this relate the question at hand?
In the way that you keep the count separate from the object.

The mapping between the count and the object is just a matter of what relation exist in the universe (or even between universes depending on the interpretation etc).

One could easily imagine a model where there are multiple views/counts of an object in different environments.

So, in essence, if you want to keep a count of something you should probably do it separately. I think it has a higher probability of being correct, but the con is it will probably impact performance a bit (I have no solid stats on it, I'm just guessing).

As I see it all boils down to if you view the universe as something that mutates itself recursively or that the universe is always new with every iteration ie Bohr vs Heisenberg etc.

Wait, is this even the right thread. Nvm, I'll post it here

Now I'm late for lunch and it's your fault! raises fist

November 15, 2021

On Monday, 15 November 2021 at 11:58:56 UTC, Stefan Koch wrote:

>

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.

I wonder if it would be interesting to have a const reference that guarantees that the underlying data-structure does not change as long as the reference or any copies of it are live? I guess that could be another reason for adding tracking of borrowing.

Use case: you obtain a record from a database thread in a transaction, when the transaction is ending the database gets to mutate the record again.

You add the constraint that only @trusted functions are allowed to create such const-references.

November 15, 2021

On 11/15/21 2:05 AM, 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.

I mean it's sound in that the type checking is valid. You are allowed to convert mutable to mutable, so having an always-mutable island is a valid. Whether it's confusing or not is a different story, and that part I agree with you.

Without additional type qualifiers, confusion would always remain.

-Steve

November 15, 2021
On Monday, 15 November 2021 at 12:24:33 UTC, Timon Gehr wrote:
> 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.

If the object is allocated, it HAS TO BE in mutable memory.
November 15, 2021

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

>

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

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.

Theres a talk on youtube by Chandler Carruth about llvm / clang optimisation and he says const is litteraly of no use at all.

November 15, 2021
On Monday, 15 November 2021 at 14:27:29 UTC, deadalnix wrote:
> On Monday, 15 November 2021 at 12:24:33 UTC, Timon Gehr wrote:
>> 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.
>
> If the object is allocated, it HAS TO BE in mutable memory.

Yes, I thought this discussion was a little bit strange, maybe because my lack of knowledge. However, if an object is allocated in the heap it has be in mutable memory.

Keep in mind that doesn't need to be the same has the type designation, immutable might be in RAM. Anyway, we can cast modify constants that are heap allocated. How does the compiler know that something is allocated on the heap?

We're still discussing around the main issue which is fixing the type system so that managed memory pointers has a distinctive type.
November 15, 2021

On Monday, 15 November 2021 at 12:58:46 UTC, Imperatorn wrote:

>

On Monday, 15 November 2021 at 09:42:03 UTC, Ola Fosheim Grøstad wrote:

>

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

Would a new keyword be required or would it be enough to specify it so that optimizations could be done etc? (So that we don't loose the "benefits" we have today). Sorry, I'm writing this the fly so haven't thought this through.

For me the right solution though seems to be keeping it "external".

Why? Don't touch the object, the usage of it is not of it's concern.

I am primarily thinking about potential use cases in metaprogramming. For instance: a hashtable that wants to treat keys as binary data and requires the key to be "fully immutable" (you don't want to hash a refcount). The hashtable does not care what the type is, it just want a definitive answer about the key's ability to change. You need more information than this, of course, you also need to know if they key is in a canonical form.

I'm starting to think that the C-style typing isn't really powerful or flexible enough to support meta-programming well. I guess such querying also could be done as a library feature, I think C++ was onto something in their library when they added some information about buffers being contiguous in memory that could be queried. Typing in languages are often on a higher abstract level, but in system level programming one often want machine level knowledge about the concrete representation.

However, doing it on the library level often requires the programmer who build types to take these needs into account, maybe there are opportunities to create robust language level inference that is better? Clearly some things cannot easily be inferred (such as whether the key is in canonical form), but maybe some things can be inferred and that would be interesting to think about.

>

Hence, it makes more sense to keep track of it in a separately, maybe even in another universe (depending on interpretation).

Yes, you could say that too. Then you are thinking about it in abstract terms.

>

Now I'm late for lunch and it's your fault! raises fist

*offers you a cup of tea*

November 15, 2021
On 15.11.21 15:27, deadalnix wrote:
> On Monday, 15 November 2021 at 12:24:33 UTC, Timon Gehr wrote:
>> 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.
> 
> If the object is allocated, it HAS TO BE in mutable memory.

No, you can allocate it on the GC heap in CTFE and then store it in the immutable data segment at runtime by assigning to a static immutable variable.

In general, you can allocate first and then change the protection attributes on the page later.
November 16, 2021
On 16/11/2021 4:23 AM, Timon Gehr wrote:
> On 15.11.21 15:27, deadalnix wrote:
>> On Monday, 15 November 2021 at 12:24:33 UTC, Timon Gehr wrote:
>>> 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.
>>
>> If the object is allocated, it HAS TO BE in mutable memory.
> 
> No, you can allocate it on the GC heap in CTFE and then store it in the immutable data segment at runtime by assigning to a static immutable variable.
> 
> In general, you can allocate first and then change the protection attributes on the page later.

Exactly.

There is nothing stopping the compiler putting immutable values in ROM, nor the user who didn't know that something like __mutable is in use from making memory they allocated read only.

const and immutables are compiler guarantees, and we shouldn't be wanting the compiler to lie to us in our misunderstandings.