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.

Reply via email to