View mode: basic / threaded / horizontal-split · Log in · Help
November 07, 2012
Struct-nested structs
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.
Top | Discussion index | About this forum | D home