Bug 18561 – postblit should allow writing const/immutable members just like constructors
Status
RESOLVED
Resolution
WONTFIX
Severity
enhancement
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2018-03-06T12:26:17Z
Last change time
2022-04-12T16:04:55Z
Assigned to
No Owner
Creator
Ate Eskola
Comments
Comment #0 by Ajieskola — 2018-03-06T12:26:17Z
This compiles:
import std.array;
import std.stdio;
import std.algorithm;
struct placeAtWorldMap
{ char[] title;
int[2] coordsMicroDeg;
this(this)
{ title = title.dup;
}
}
void main()
{ char[] title = "London bridge".dup;
const place = placeAtWorldMap(title, [51_508_038, -87_693]);
const samePlace = place;
"falling down ".copy(title);
place.title.writeln; // falling down
samePlace.title.writeln; // London bridge
readln;
}
This does not:
import std.array;
import std.stdio;
import std.algorithm;
struct placeAtWorldMap
{ const char[] title;
int[2] coordsMicroDeg;
this(char[] name, int[2] coords)
{ // you can assign const members here
this.title = name;
this.coordsMicroDeg = coords;
}
this(this)
{ // remove to compile
title = title.dup; // cannot modify ´const´ expression ´this.title´
}
}
void main()
{ char[] title = "London bridge".dup;
const place = placeAtWorldMap(title, [51_508_038, -87_693]);
const newPlace = placeAtWorldMap("Big Ben".dup, [51_500_749, -124_611]);
const samePlace = place;
"falling down ".copy(title);
place.title.writeln; // falling down
samePlace.title.writeln; // London bridge (but falling down without the postblit causing the error)
newPlace.title.writeln; // Big Ben
}
Postblits behave inconsistently with constants. As shown in the second example, it cannot modify members which are declared as const. But if that is wrong, the first one should compile neither, as all the members should be treated as const when the whole variable is const.
Postblits should behave either like member functions -no mutation of const whatsover- or like constructors -allow mutating the variable once-.
I tend to think it should be the latter of the two, since postblits are initializing an object, just like constructiors.
Comment #1 by ag0aep6g — 2018-03-06T12:56:29Z
(In reply to Ajieskola from comment #0)
> Postblits behave inconsistently with constants. As shown in the second
> example, it cannot modify members which are declared as const. But if that
> is wrong, the first one should compile neither, as all the members should be
> treated as const when the whole variable is const.
The first example shouldn't compile.
`title = title.dup;` doesn't do any actual harm, because you're not altering the original. But consider `title[0] = 'W';`. Now you're changing the original `title` to "Wondon bridge", and you're doing it through a `const` reference. That should not be possible. Even worse, the original title could be `immutable`:
----
import std.stdio;
struct placeAtWorldMap
{ char[] title;
this(this)
{ title[0] = 'W'; /* ! */
}
}
void main()
{ immutable char[] title = "London bridge".dup;
const place = const placeAtWorldMap(title);
const samePlace = place;
title.writeln; // Wondon bridge
}
----
Issue 18357 already covers that problem. Closing as DUPLICATE. Feel free to revert if you think it's not an exact duplicate.
*** This issue has been marked as a duplicate of issue 18357 ***
Comment #2 by schveiguy — 2018-03-06T13:30:43Z
I think the OP has a point here.
A more direct example:
struct S
{
const char[] t;
this(this)
{
t = t.dup; // this should be allowed
// t[0] = 'w'; // this should not
}
}
S s;
// Should be OK, calls postblit, s2 is new data.
auto s2 = s;
// error cannot overwrite const (does not call postblit). This happens already
s = s2;
essentially, when READING `this`, all normal rules apply. When WRITING members of `this`, everything should be considered tail-X, where X is const, immutable, etc. If we have any immutable or const data as members, the compiler should have already forbade it if you couldn't overwrite it before the postblit.
It's the same as constructors, but for constructors, `this` didn't exist yet. If we get to a postblit on a type that has const or immutable data, we have the same guarantee.
This does not address postblits being called on const data types (with `this` being mutable during the postblit). That is a different bug.
Comment #3 by dfj1esp02 — 2018-03-06T18:16:55Z
This passes:
---
struct A
{
int a;
this(int b) const { a=b; }
}
int main()
{
const A a;
assert(a.a==0,"0");
a.__ctor(1);
assert(a.a==1,"1");
return 0;
}
---
Comment #4 by Ajieskola — 2018-03-06T20:04:51Z
(In reply to anonymous4 from comment #3)
> This passes:
> ---
> struct A
> {
> int a;
> this(int b) const { a=b; }
> }
> int main()
> {
> const A a;
> assert(a.a==0,"0");
> a.__ctor(1);
> assert(a.a==1,"1");
> return 0;
> }
> ---
I believe it should not. Yes, constructor should be able to do that, but only when used as a constructor. But it is a separate issue from this one.
Comment #5 by schveiguy — 2018-03-06T20:10:15Z
(In reply to anonymous4 from comment #3)
> a.__ctor(1);
This is another bug. One should only be able to call const __ctor on a struct once, before using it.
Comment #6 by dfj1esp02 — 2018-03-09T11:09:19Z
(In reply to Steven Schveighoffer from comment #2)
> This does not address postblits being called on const data types (with
> `this` being mutable during the postblit). That is a different bug.
I thought you meant this. As you can see const constructor can be already called on const data, ability to call const postblit wouldn't be different.
Comment #7 by razvan.nitu1305 — 2022-04-12T11:43:07Z
Postblit is a flawed design and will not be pursued. Closing this as WONTFIX.
Comment #8 by Ajieskola — 2022-04-12T16:04:55Z
And the issue is in practice solved by copy constructors anyway, thanks to you :). They didn't exist when I raised this issue but now they do.