Rebooting the __metada/__mutable discussion

RazvanN razvan.nitu1305 at gmail.com
Wed Apr 6 09:41:52 UTC 2022


Hello everyone,

Lately, I've been looking at the __metadata/__mutable 
discussions. For reference, here is the material I have so far:

1. Forum discussion: 
https://forum.dlang.org/thread/3f1f9263-88d8-fbf7-a8c5-b3a2a5224ce0@erdani.org?page=1

2. Timon's original DIP: 
https://github.com/RazvanN7/DIPs/blob/Mutable_Dip/DIPs/timon_dip.md

3. My updated DIP which is based on Timon's: 
https://github.com/RazvanN7/DIPs/blob/Mutable_Dip/DIPs/DIP1xxx-rn.md

We need this to be able to implement generic reference counting. 
So our main
problem is how do we reference count immutable/const objects. 
Timon's original
proposal tried to implement __metadata in a way that does not 
affect purity
based optimizations. I think that this could be done:

1. A strongly pure function (that return types without 
indirections) will return the same result when applied to the 
same immutable arguments.

Fixed by rewritting

```d
auto a = foo(arg)   // foo -> strongly pure
aubo b = foo(arg)
````

to

```d
auto a = foo(arg)
auto b = a
```

This is taken from Timon DIP.

2. The set of references returned from strongly pure functions 
can be safely converted to immutable or shared.

This is no affected by the introduction of __metadata.

3. A strongly pure function whose result is not used may be 
safely elided.

```d
struct S{
     private int __metadata x;
}

void foo(immutable ref S s)pure{
     s.x += 1;
}

void main(){
     immutable S s;
     foo(s); // there is no reason for this call to happen
     assert(s.x==1); // can't rely on this, it might also be 0
}
```

Essentially, if `foo` is strongly pure, then the compiler can 
optimize away
the call to it and your reference count is blown away. If we look 
at it this
way, the problem seems to be unsolvable. However, the idea of 
__metadata is to
be used solely by library developers and even they should take 
extra care.
As such, I would propose that `__metadata` can only be accessed 
from inside
the aggregate that defines it (`private` here means `Java 
private`) and methods
that access __metadata directly need to also private. I think 
that this makes sense since the reference is updated only when 
you call the copy constructor and the assignment operator. These 
methods should be public and they can call the incRef, decRef 
that are mandatory private. This way, it becomes impossible to 
access a `__metadata` field without going through the object 
methods. This makes sense, since the object is the only one that 
should manage the `__metadata`.

Now, if we do it like this, then `foo` will not have any means of 
accessing `x`
apart from assigning s, passing s to a function or copy 
constructing from s.
However, whatever happens to s, once the execution of `foo` is 
over, the reference
count at the call site is going to be the same as when `foo` was 
called. Why?
Because there is no way you can escape any reference to s outside 
of a strongly pure function (other than returning it, but that 
case is taken care of at point 1.).

4. If we have two subsequent pure function invocations 
foo(args1...) and bar(args2...) where data transitively reachable 
from args1 and args2 only overlaps in immutable and const data 
(this includes data accessed through __mutable fields of const 
and immutable objects), the two invocations may safely swap their 
order (of course, this only applies if none of the two functions 
takes arguments)

This should be un-affected.

5. A strongly pure function invocation can always exchange order 
with an adjacent impure function invocation.

This should be un-affected.

What do you think? Am I missing anything? If you think this could 
fly, I could update the DIP and submit it.

Best regards,
RazvanN


More information about the Digitalmars-d mailing list