www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Issues with immutable/inout

reply burt <invalid_email_address cab.abc> writes:
Hello,

Since D's const, immutable and inout are transitive, it is more 
difficult to write const-correct code. Recently I tried writing a 
library with `immutable` in mind, but I feel like mutable and 
immutable cannot be mixed: you can only choose one.

The reason I think this is a couple of issues. The following code 
demonstrates the problem:

```
import std;

abstract class Base
{
     immutable int i;

     this(int i)  safe /*inout? (1)*/
     {
         this.i = i;
     }

     void update()  safe /*mutable*/;
}

final class SingletonDerived : Base
{
     static immutable SingletonDerived instance;
     shared static this() /* safe*/
     {
         // I want this:
         //instance = new immutable SingletonDerived(42);
         // or this:
         //instance = new SingletonDerived(42);

         // but I have to use this, which is not  safe:
         instance = cast(immutable) new SingletonDerived(42);
     }

     override void update()  safe const
     {
         //nothing
     }

private:
     this(int i)  safe /*inout? (1)*/
     {
         super(i);
     }
}

void func(Base object)  safe
{
     object.update();
}

 safe unittest
{
     // cast is not  safe, and I would rather use  system only 
where necessary (2)
     auto object = (()  trusted => cast() 
SingletonDerived.instance)();
     assert(object !is null);
     func(object);
}
``` (compile with -main -unittest)

Problem (1): class constructors cannot be called with different 
mutabilities. When marking the constructor as mutable, you cannot 
create immutable objects; when marking as inout or immutable, it 
doesn't work either.

Problem (2): cannot (implicitly/safely) convert between immutable 
and mutable objects, even if the class is final and contains only 
immutable fields. It is bad that immutable applies to the class 
reference, and not to the underlying object.

I feel like D would be a lot more usable for me if these two 
issues were fixed. However, fixing problem 2 probably requires a 
change in the spec and in the language. Does such a change 
require a DIP or is a bug report enough? Or is there a different 
( safe) solution that I overlooked?
May 15 2020
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 15.05.20 12:13, burt wrote:
 Hello,
 
 Since D's const, immutable and inout are transitive, it is more 
 difficult to write const-correct code.
There's no such thing. This is a C++-ism.
 ...
 
 Problem (1): class constructors cannot be called with different 
 mutabilities. When marking the constructor as mutable, you cannot create 
 immutable objects; when marking as inout or immutable, it doesn't work 
 either.
 ...
`inout` is supposed to work. I think this is a regression. Not sure when it happened but it was between 2.060 and 2.070.1.
 Problem (2): cannot (implicitly/safely) convert between immutable and 
 mutable objects, even if the class is final and contains only immutable 
 fields. It is bad that immutable applies to the class reference, and not 
 to the underlying object.
 ...
I agree. One way to make some progress on this would be to give special semantics to `immutable`/`shared`/... classes. (I.e., enable conversion between references of different mutabilities.)
 I feel like D would be a lot more usable for me if these two issues were 
 fixed. However, fixing problem 2 probably requires a change in the spec 
 and in the language. Does such a change require a DIP or is a bug report 
 enough? Or is there a different ( safe) solution that I overlooked?
 
Mark the constructors `pure` and it will work.
May 15 2020
next sibling parent burt <invalid_email_address cab.abc> writes:
On Friday, 15 May 2020 at 11:08:36 UTC, Timon Gehr wrote:
 On 15.05.20 12:13, burt wrote:
 Hello,
 
 Since D's const, immutable and inout are transitive, it is 
 more difficult to write const-correct code.
There's no such thing. This is a C++-ism.
Oh, I did not know that. I assumed it referred to marking the right things const to signal it won't or shouldn't mutate.
 ...
 
 Problem (1): class constructors cannot be called with 
 different mutabilities. When marking the constructor as 
 mutable, you cannot create immutable objects; when marking as 
 inout or immutable, it doesn't work either.
 ...
`inout` is supposed to work. I think this is a regression. Not sure when it happened but it was between 2.060 and 2.070.1.
According to run.dlang.io, it stopped working in 2.063. I'm guessing it was caused by https://dlang.org/changelog/2.063.html#ctorqualifier. I can't really find out what PR caused it though.
 ...
 Mark the constructors `pure` and it will work.
Thanks, but this appears to only work with non-reference types: ``` //Compared to this: //alias T = int; alias T = char[]; class B { T x; this(inout T x) inout pure { this.x = x; } } void main() {} unittest { auto b = new immutable B(T.init); } ``` (Compile with -unittest)
May 15 2020
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Friday, 15 May 2020 at 11:08:36 UTC, Timon Gehr wrote:
 On 15.05.20 12:13, burt wrote:
 Hello,
 
 Since D's const, immutable and inout are transitive, it is 
 more difficult to write const-correct code.
There's no such thing. This is a C++-ism.
In D I just take it to mean "usable with const or immutable instances". It's a shame (to me at least!) that the default is a mutable `this`.
May 15 2020
parent Seb <seb wilzba.ch> writes:
On Friday, 15 May 2020 at 14:38:54 UTC, Atila Neves wrote:
 On Friday, 15 May 2020 at 11:08:36 UTC, Timon Gehr wrote:
 On 15.05.20 12:13, burt wrote:
 Hello,
 
 Since D's const, immutable and inout are transitive, it is 
 more difficult to write const-correct code.
There's no such thing. This is a C++-ism.
In D I just take it to mean "usable with const or immutable instances". It's a shame (to me at least!) that the default is a mutable `this`.
Yes, a preview flag to change the defaults would be very much appreciated! Though I guess a pragma or similar to change the shameful defaults on a per package-basis would even be better ;-)
May 15 2020