Gotcha. I guess I can see how special casing them is akward for the compiler.
I guess I donât see how a user defined, zero sized type might not be zero sized though. And if it must always be zero sized, then extern or auto wouldnât seem to matter. Unless there are some language features making them incompatible.
you simply canât define a zero sized type with an auto struct, as the size is an implementation detail of the compiler.
And there is no reason âemptyâ auto structs should be exempt from hidden safety fields, they can be instantiated and used, even if they shouldnât be.
Yes thats what I was using. Nothing wrong with extern struct - both are equal for my use case. Not really an ah-ha moment but I just didnât think to use an enum
I realize itâs kinda niche, but when interfacing with object oriented code, like Windowsâ COM, structs need to be laid out according to the inherintance rules, and you are expected to extend their structs. After going through some callbacks, you get your struct back. You donât really care how your own struct is laid out internally, but you have to embed it into an extern struct so that you can work with the system. In code, it looks like this:
const SystemProvidedStruct = extern struct{
some_field: u8,
// Your struct goes here
};
const MyStruct = struct{
data: u8,
};
const EmbedMyStruct = extern struct{
header: SystemProvidedStruct,
my_struct: MyStruct, // doesn't work because MyStruct is not extern
};
pub extern "system" registerObject(*SystemProvidedStruct) void;
var my_var: MyEmbedStruct = ...;
registerObject(&my_var.header);
// At a later time, you get this pointer back, and you obtain your struct
// with @fieldParentPtr
const SystemProvidedStruct = extern struct{
some_field: u8,
// Your struct goes here
};
const MyStruct = struct{
data: u8,
pub const init: MyStruct = ...;
};
const EmbedMyStruct = extern struct{
header: SystemProvidedStruct,
my_struct_bytes: [@sizeOf(MyStruct)]u8 align(@alignerOf(MyStruct)),
};
pub extern "system" registerObject(*SystemProvidedStruct) void;
var my_var: MyEmbedStruct = .{
.header = ...,
.my_struct_bytes = std.mem.toBytes(MyStruct.init),
};
registerObject(&my_var.header);
// At a later time, you get this pointer back, and you obtain your struct
// with @fieldParentPtr
const my_var: *MyEmbedStruct = @fieldParentPtr("header ", header);
const my_struct: *MyStruct = std.mem.bytesAsValue(MyStruct, &my_var.my_struct_bytes);
In this use case, our data is actually just some type-erased bytes.
What may be worth discussing is that toBytes has the potential for extra copying, which could become a problem after PRO and RLS are removed.
Thatâs an interesting solution. my_struct_bytes would also have to be aligned by MyStruct alignment. Next time Iâm doing COM, Iâll check this out.