On Saturday, 19 November 2022 at 09:26:49 UTC, Andrey Zherikov
wrote:
On Saturday, 19 November 2022 at 09:12:26 UTC, thebluepandabear
wrote:
That's the point many people have given here which is not
convincing him, even though it is quite great.
I think we all know the answer here 😂
IMHO you are both right :)
You are speaking about API compatibility, `[]() {}()` speaks
about ABI compatibility. The latter makes sense in long-running
production software. So we know that there are no issues in API
compatibility but we don't know anything about ABI.
Yes, this is a good summary. Redefining a raw field as a
getter/setter pair keeps the API but breaks the ABI, so in some
cases conservative getters/setters can be justified.
Another problem with raw fields:
```D
struct S{int field;}
@safe clientCode()
{ auto s = new S();
doSomething(&s.field);
}
```
This will break if S is rewritten as
```D
struct S
{ int field_;
auto field(){return field_;}
auto field(int val){return field_ = val;}
}
```
I though at first that breakage could still be avoided by instead
writing
```D
struct S
{ int field_;
ref field(){return field_;}
}
```
...but I tested and actually it does not work because in this
case `&s.field` takes the address of the getter function, not the
field.
Now, despite all this I don't think it'd be a good idea to write
everything to getters/setters just in case. The binary interface
issue is frankly secondary: most structs and classes are just
compiled along with their client code. And even separately
compiled libraries only have to do this if they strive to provide
a stable ABI between releases, which is not nearly always the
case. Nor needs to be.
But still the pointer problem in the above example stands, so
conservative getters/setters are justified in an API that's used
widely enough. But probably not for something internal to a ten
thousand line long package.