August 01, 2021

On Friday, 30 July 2021 at 19:17:55 UTC, Michael Galuza wrote:

>

Is there any analogue of C++ mutable in D? As far as I understand, this is impossible due to transitive constness, but maybe some variation of Rebindable will be useful?

P.S. Of course I mean 'fair' mutable, not qualifier-away cast().

Let's slightly reformulate my question. Can we write in D smth like this:

struct Mutable(T) { /* magic */ }

struct Shape {
    private Mutable!double area;

    double getArea() const {
        if (area == 0) { area = computeArea(); }
        return area;
    }
}

In other words, can we implement method void S.opAssign(T value) const of some struct S which change internal state of S and this method doesn't have UB and doesn't break D's type system.

August 01, 2021

On Sunday, 1 August 2021 at 18:21:32 UTC, Michael Galuza wrote:

>

In other words, can we implement method void S.opAssign(T value) const of some struct S which change internal state of S and this method doesn't have UB and doesn't break D's type system.

No. Mutating an object typed as const is always UB in D.

August 01, 2021

On Friday, 30 July 2021 at 19:17:55 UTC, Michael Galuza wrote:

>

Is there any analogue of C++ mutable in D? As far as I understand, this is impossible due to transitive constness, but maybe some variation of Rebindable will be useful?

P.S. Of course I mean 'fair' mutable, not qualifier-away cast().

Not possible as other people mentioned. In this case the best approach would be to either design your struct to contain const and mutable fields, and design it's interface accordingly, or you could make a mutable decorator that would be mutable and expose mutable aspects, while keeping the decorated instance const.

Best regards,
Alexandru.

August 02, 2021

On 8/1/21 2:21 PM, Michael Galuza wrote:

>

On Friday, 30 July 2021 at 19:17:55 UTC, Michael Galuza wrote:

>

Is there any analogue of C++ mutable in D? As far as I understand, this is impossible due to transitive constness, but maybe some variation of Rebindable will be useful?

P.S. Of course I mean 'fair' mutable, not qualifier-away cast().

Let's slightly reformulate my question. Can we write in D smth like this:

struct Mutable(T) { /* magic */ }

struct Shape {
     private Mutable!double area;

     double getArea() const {
         if (area == 0) { area = computeArea(); }
         return area;
     }
}

In other words, can we implement method void S.opAssign(T value) const of some struct S which change internal state of S and this method doesn't have UB and doesn't break D's type system.

Yes. You need to use global space to do it.

e.g.:


struct Shape {
   private static double[size_t] areaLookup;
   private const size_t magicNumber; // set on constructor
   double getArea() const {
      return areaLookup.require(magicNumber, computeArea());
   }
}

I've argued in the past that since this is possible, putting the memory inside (or along-side) the instance isn't all that different, and there are surely other typesystem-allowable ways (I think there was a plan at some point to use affixAllocator to do something like this). But "possible" here is not exactly equivalent to "desirable". What you need is some way to clarify that the "mutable" data is not actually part of the instance, but some nebulous region that is carried along with it.

-Steve

August 03, 2021

On Friday, 30 July 2021 at 19:17:55 UTC, Michael Galuza wrote:

>

[snip]

We are saying that there is no direct analogue for mutable in D. It turns out we were all wrong - there is, and it even works in @safe! Behold:

@safe:
alias MutableDel(T) = @safe ref T delegate();

struct Foo
{ int normalMember;
  private MutableDel!int _mutableMember;
  ref mutableMember() const {return _mutableMember();}

  this(int a, int b)
  { normalMember = a;
    _mutableMember = makeMutable(b);
  }
}

MutableDel!T makeMutable(T)(T mem) @safe
{ auto varArr = [mem];
  return ref () => varArr[0];
}


void main()
{ import std;

  const foo = Foo(5, 10);
  foo.mutableMember.writeln; //10
  foo.mutableMember = 15;
  foo.mutableMember.writeln;
}

Now, I definitely don't recommend using this. It might well end up being considered as a bug, and thus stop working in the future. Also the optimizer might not take this possibility into account, thus injecting bugs to your code.

August 03, 2021

On Tuesday, 3 August 2021 at 13:02:38 UTC, Dukc wrote:

>

Now, I definitely don't recommend using this. It might well end up being considered as a bug, and thus stop working in the future. Also the optimizer might not take this possibility into account, thus injecting bugs to your code.

It's a known bug, since 2008:

https://issues.dlang.org/show_bug.cgi?id=1983

August 03, 2021

On Tuesday, 3 August 2021 at 14:01:20 UTC, Paul Backus wrote:

>

On Tuesday, 3 August 2021 at 13:02:38 UTC, Dukc wrote:

>

Now, I definitely don't recommend using this. It might well end up being considered as a bug, and thus stop working in the future. Also the optimizer might not take this possibility into account, thus injecting bugs to your code.

It's a known bug, since 2008:

https://issues.dlang.org/show_bug.cgi?id=1983

I don't think it's that one. I'm not abusing the delegates context pointer mutablity, I'm abusing the fact that a const or immutable delegate may have a mutable return type:

@safe:

void main()
{ import std;
  auto varArr = [5];

  immutable del = () => varArr[0];
  del().writeln;
  varArr[0] = 10;
  del().writeln;
}
August 03, 2021

On Tuesday, 3 August 2021 at 15:33:34 UTC, Dukc wrote:

>

On Tuesday, 3 August 2021 at 14:01:20 UTC, Paul Backus wrote:

>

https://issues.dlang.org/show_bug.cgi?id=1983

I don't think it's that one. I'm not abusing the delegates context pointer mutablity, I'm abusing the fact that a const or immutable delegate may have a mutable return type:

@safe:

void main()
{ import std;
  auto varArr = [5];

  immutable del = () => varArr[0];
  del().writeln;
  varArr[0] = 10;
  del().writeln;
}

This example is abusing the fact that an immutable delegate can have a mutable context pointer--i.e., that immutability of delegate contexts is not transitive. If you try to replace the delegate with a user-defined type...

struct Delegate
{
    int* context;
    this(int* p) { context = p; }
    int opCall() { return *context; }
}

void main()
{
    int* p = new int(5);
    immutable dg = Delegate(p);
}

The compiler correctly points out that the conversion to immutable is invalid:

>

Error: cannot implicitly convert expression Delegate(null).this(p) of type Delegate to immutable(Delegate)

You're right, though, that it's not exactly issue 1983. I think the bugzilla issue for this specific case is https://issues.dlang.org/show_bug.cgi?id=16058.

1 2
Next ›   Last »