Struct-nested structs
Andrej Mitrovic
andrej.mitrovich at gmail.com
Tue Nov 6 22:30:24 PST 2012
I don't know whether it's ever planned that the following is
supported, but every so often I see bearophile keep mentioning that it
will be supported so I want to state my opinion on this:
```d
struct A
{
int bb;
struct B
{
void inc() { bb++; }
byte b;
}
}
```
Is this really a feature in the making?
If this becomes supported it can cause subtle issues when interfacing
with C. You could accidentally create a hidden field by accessing a
field from an outer scope (accidents happen..), and you wouldn't know
anything is wrong until you'd either get a crash, or corrupt data, or
worse, data that is missing because it was written to a context field
without you knowing.
For example maybe you're calling some external C function that fills
your struct with whatever data but needs to know the size of the
struct:
A.B struct;
cFunc(&struct, sizeof(A.B))
Whoops! You thought cFunc is going to write over the 1-byte field
'data', but it will actually write anywhere from 8-bytes to 16-bytes
(based on whether x64 is in play) over the context pointer. So at
first glance it will appear as though you're getting incomplete data
from the C function.
But it's not just interfacing with C, you could have D code that
relies on a struct being the size of its member fields. Sure you could
use `static assert(typeof(this).sizeof == 1)`, but that relies on
convention.
And if we're going to be forced to write `static struct` everywhere
then we might as well say structs are not POD by default. I'm against
this feature because we already have a definition that says structs
are POD, and they're used immensely when interfacing with C. Having
them *magically* insert a context pointer by a simple typo is way too
dangerous.
Note that the OP sample had a typo, it increments 'bb' instead of 'b',
so this would create a context pointer and make A.B either 8 or 12
bytes in size (1 byte for 'data' field, 4 or 8 bytes for the context
pointer, and the rest is due to alignment).
With classes this is isn't a problem since you use special syntax in
order to instantiate a nested class and this typo would never pass the
compilation stage. But with structs having a defined .init property
you could easily end up using a struct-nested struct which isn't a POD
type even though you assumed it is. "static struct" comes to the
rescue, but it relies solely on convention.
More information about the Digitalmars-d
mailing list