D does have head const (but maybe it shouldn't)

Timon Gehr timon.gehr at gmx.ch
Wed Dec 30 22:49:09 UTC 2020


On 29.12.20 17:15, ag0aep6g wrote:
> Exercise: Consider the following `main` function. Define `f` and `g` so 
> that the code is valid, compiles, and runs successfully. The asserts 
> must be executed and they must pass.
> 
> ----
> void main() pure @safe
> {
>      int* x = new int;
>      const y = f(x);
>      *x = 1;
>      g(y);
>      assert(*x == 2);
> }
> ----
> 
> Hints:
> * You can't store `x` in a global because the code is `pure`.
> * You can't cast `const` away in `g` because that would be invalid.
> * You're supposed to find a type for which `const` means head const.
> 
> Solution: https://run.dlang.io/is/dsaGFS
> 
> The validity of the given solution might be arguable, and I'd be in 
> favour of outlawing it. It's surprising that there's a type for which 
> `const` means head const when it means transitive const for everything 
> else. It's so surprising that even DMD trips over it 
> (<https://issues.dlang.org/show_bug.cgi?id=21511>).

It's a bug. Here's a number of such "solutions" with links to the 
corresponding bug reports, the last one is the same as your suggested 
solution. They are all type system holes on the same level: they break 
aliasing invariants that the type system is supposed to preserve in 
`pure @safe` code.

---
// https://issues.dlang.org/show_bug.cgi?id=17744
int* f(int* x)pure @safe{ return x; }
void g(const(int)* y)pure @safe{
     inout(int)* delegate(inout(int)*)pure @safe delegate()pure @safe 
foo(inout(int)* y)pure @safe{
         inout(int)* bar(inout(int)* p)pure @safe{
             return y;
         }
         return ()=>&bar;
     }
     int* x;
     *foo(y)()(x)=2;
}
---

---
// https://issues.dlang.org/show_bug.cgi?id=18566
auto f(int* x)pure @safe{
     struct S{
         void foo()const pure{
             *x=2;
         }
     }
     return S();
}
void g(S)(S s){ s.foo(); }
---

---
// https://issues.dlang.org/show_bug.cgi?id=21517
// (this one is new, I found this while solving the challenge)
auto f(int* x)pure @safe{ return x; }
void g(const(int)* y)pure @safe{
     int* foo(inout(int)* x)pure @safe{
         int* bar(inout(int)* delegate(inout int)pure @safe z){
             return z(2);
         }
         return bar((inout t)=>x);
     }
     *foo(y)=2;
}
---

---
// https://issues.dlang.org/show_bug.cgi?id=2947
class C{ int*[] a=[null]; }
auto f(int* x)pure @safe{
     (new C).a[0]=x;
     return x;
}
void g(const(int)* y)pure @safe{
     *(new C).a[0]=2;
}
---

---
// https://issues.dlang.org/show_bug.cgi?id=9149#c11
auto f(int* x)pure @safe{
     return (){ *x=2; };
}
auto g(void delegate()pure @safe dg)pure @safe{
     dg();
}
---


More information about the Digitalmars-d mailing list