Thread overview
What is the Status of __mutable ?
Dec 20, 2018
Vijay Nayar
Dec 20, 2018
Nicholas Wilson
Dec 20, 2018
Kagamin
Dec 20, 2018
Kagamin
Dec 20, 2018
Neia Neutuladh
December 20, 2018
During the DConf of 2018, there was a talk about possibly introducing __mutable into the D Language, which has utility in allowing synchronization objects like locks, reference counts, and lazy initialization to be used for objects that are otherwise const or immutable. It was also stated that reference counts are already being maintained by the "monitor", which I know little about other than that it's built into the language and that user code does not have the same privileges.

However, the __mutable feature could open up problems in terms of the compiler's ability to optimize generated code and knowing which CPU L1/L2 caches are valid or not.

What is the current status of this work? Have there been any significant or unexpected hurdles that have come up? Any major accomplishments?

The most significant reason for my question is my own ignorance of the normal communication channels in use. Apologies for the spam if this information has already been shared elsewhere, but a link to that information would be appreciated.
December 20, 2018
On Thursday, 20 December 2018 at 10:47:18 UTC, Vijay Nayar wrote:
> During the DConf of 2018, there was a talk about possibly introducing __mutable into the D Language, which has utility in allowing synchronization objects like locks, reference counts, and lazy initialization to be used for objects that are otherwise const or immutable. It was also stated that reference counts are already being maintained by the "monitor", which I know little about other than that it's built into the language and that user code does not have the same privileges.
>
> However, the __mutable feature could open up problems in terms of the compiler's ability to optimize generated code and knowing which CPU L1/L2 caches are valid or not.
>
> What is the current status of this work? Have there been any significant or unexpected hurdles that have come up? Any major accomplishments?
>
> The most significant reason for my question is my own ignorance of the normal communication channels in use. Apologies for the spam if this information has already been shared elsewhere, but a link to that information would be appreciated.

There is an implementation laying about in the PR queue: https://github.com/dlang/dmd/pull/8315

IIRC the motivating examples for __mutable were:
* Monitor for immutable classes
* Refcount fields for RC objects
* References to allocators in immutable containers

Immutable monitors can use a singleton mutex.
For RC objects I'd rather see opHeadMutable implemented (const T!B <-> T!(const B) ).
I'm not convinced of the utility of immutable containers (not to be confused with containers with immutable elements which are useful), see also opHeadMutable.
December 20, 2018
How about this?

struct __mutable(T)
{
    private size_t _ref;
    this(T val){ _ref=cast(size_t)val; }
    T unwrap() const
    {
        return cast(T)_ref;
    }
}

struct A
{
    __mutable!(int*) rc;
    this(int) immutable
    {
        rc=new int;
    }
    int inc() immutable
    {
        return ++*rc.unwrap;
    }
}

int main()
{
    immutable A b=0;
    assert(b.inc==1);
    assert(b.inc==2);
    return 0;
}

I think it doesn't violate type system (formally): the mutable location is never seen as immutable, so immutability is not casted away, but it's not rebindable.
December 20, 2018
On 12/20/18 10:10 AM, Kagamin wrote:
> How about this?
> 
> struct __mutable(T)
> {
>      private size_t _ref;
>      this(T val){ _ref=cast(size_t)val; }
>      T unwrap() const
>      {
>          return cast(T)_ref;
>      }
> }
> 
> struct A
> {
>      __mutable!(int*) rc;
>      this(int) immutable
>      {
>          rc=new int;
>      }
>      int inc() immutable
>      {
>          return ++*rc.unwrap;
>      }
> }
> 
> int main()
> {
>      immutable A b=0;
>      assert(b.inc==1);
>      assert(b.inc==2);
>      return 0;
> }
> 
> I think it doesn't violate type system (formally): the mutable location is never seen as immutable, so immutability is not casted away, but it's not rebindable.

The biggest issue is that immutable is implicitly shared.

-Steve
December 20, 2018
On Thursday, 20 December 2018 at 15:19:39 UTC, Steven Schveighoffer wrote:
> The biggest issue is that immutable is implicitly shared.

struct __mutable(T)
{
    private size_t _ref;
    this(shared T val){ _ref=cast(size_t)val; }
    shared(T) unwrap() const
    {
        return cast(shared T)_ref;
    }
}

struct A
{
    __mutable!(int*) rc;
    this(int) immutable
    {
        rc=new shared int;
    }
    int inc() immutable
    {
        import core.atomic;
        return atomicOp!"+="(*rc.unwrap,1);
    }
}

int main()
{
    immutable A b=0;
    assert(b.inc==1);
    assert(b.inc==2);
    return 0;
}
December 20, 2018
On Thu, 20 Dec 2018 10:47:18 +0000, Vijay Nayar wrote:
> However, the __mutable feature could open up problems in terms of the compiler's ability to optimize generated code and knowing which CPU L1/L2 caches are valid or not.

More importantly, immutable is the same as shared immutable right now. That would have to change.