digitalmars.D - Structs can't be zero bytes in size?
- Dylan Knutson (80/80) Sep 02 2013 Take a look at this:
- Dylan Knutson (3/3) Sep 02 2013 My current workaround is to use `Foo.tupleof.length == 0` to
- Andrej Mitrovic (27/29) Sep 02 2013 I suggest:
- Walter Bright (3/4) Sep 02 2013 It comes from C. This was done in C so that addresses of struct instance...
- Vladimir Panteleev (4/8) Sep 02 2013 Why is that important, and why does D need it?
- Lionello Lunesu (4/13) Sep 02 2013 struct Z {};
- Andrej Mitrovic (3/6) Sep 02 2013 Since the structs are declared empty, their 1-byte values don't
- Lionello Lunesu (7/13) Sep 04 2013 It has to do with the ol' 'identity vs equality'. In the example above,
- Vladimir Panteleev (5/23) Sep 02 2013 Yes, but why is this important? If you declare Z as "alias int[0]
- growler (19/43) Sep 02 2013 alias int[0] Y;
- Vladimir Panteleev (3/5) Sep 02 2013 Why? What do you need that assumption for? What will break if the
- growler (5/10) Sep 02 2013 There's no real reason, it's just a personal preference. As I
- Walter Bright (5/14) Sep 02 2013 There were huge debates about this back when the C standard was in devel...
- Dylan Knutson (8/13) Sep 02 2013 Fair enough. Was there any discussion on these forums about it?
- Walter Bright (4/15) Sep 02 2013 Not following this aspect of C would result in silent and unexpected cha...
- Dylan Knutson (3/6) Sep 02 2013 Fair enough. I'll guess stick with `SomeStruct.tupleof.length ==
- Piotr Szturmaj (3/26) Sep 03 2013 How about specifying extern(C) before each C structure? The majority of
- Walter Bright (2/4) Sep 03 2013 While we could do that, at what point does this become arcane complexity...
- Dylan Knutson (20/26) Sep 03 2013 I think it depends how much metaprogramming could benefit in the
- Walter Bright (4/11) Sep 03 2013 If you need a zero sized object in D,
- Dylan Knutson (25/27) Sep 03 2013 I tried that, but unfortunately std.variant isn't compatible with
- Andrej Mitrovic (4/6) Sep 03 2013 Please do file this as a bug:
- Dylan Knutson (5/12) Sep 03 2013 Reported. I didn't realize this wasn't the intended behavior of
- Dylan Knutson (4/8) Sep 02 2013 So, because backwards compatibility is an important
- Walter Bright (7/15) Sep 03 2013 Some background:
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (10/11) Sep 03 2013 Ooh! This one has a very interesting excerpt:
- Walter Bright (2/12) Sep 03 2013 In C++ it is defined.
Take a look at this: http://dpaste.dzfl.pl/6bf578a3 ``` struct Foo {} pragma(msg, Foo.sizeof); void main() {} ``` output: 1LU It seems like structs can't have a size of zero, but this doesn't make a whole lot of sense semantically. I've currently got a project using `std.variant : Algebraic`, so a struct which simply acts as a distinct type would be useful to have. Take, for example, a simple client-server payload passing implementation: ``` enum PayloadType { response_success, response_failure } alias Payload = Algebraic!( ResponseSuccess, ResponseFailure); struct ResponseSuccess { static type = PayloadType.response_success; } struct ResponseFailure { static type = PayloadType.response_failure; uint code; } // Then pseudocode for how the structure is sent over a connection void sendPayload(Resp)(Resp response, OutputStream conn) { conn.write(Resp.type); static if(Resp.sizeof) { // Always triggered, even for empty structs. conn.write(response); } } // And how it's recieved from a connection Payload recievePayload(InputStream conn) { PayloadType type = conn.read!PayloadType(); Payload ret; final switch(type) with(PayloadType) { case response_success: // Nothing actually needs to be read from the stream, // but 1 byte extra is written anyways because ResponseSuccess is 1 byte. ubyte throwaway = conn.read!ubyte(); ret = ResponseSuccess(); break; case response_failure: ResponseFailure failure = conn.read!ResponseFailure(); ret = failure; break; } return ret; } // Usage: auto conn = new InputOutputStream(); //Responds to .read() and .write() conn.sendPayload(ReponseSuccess()); conn.recievePayload().visit!( (ResponseSuccess resp) { writeln("Success!"); }, (ResponseFailure resp) { writeln("Failure! Code: ", resp.code); } )() ``` In the above example, if ResponseSuccess had a size of zero, there would be no additional network overhead. However, because the extra byte of `response` is written to the stream, one must read an empty byte on the recieving end, and throw it away. In this case, it accounts for 33% of the network overhead for transferring a ResponseSuccess structure. 2 bytes for the type of struct, and then 1 additional empty byte... just because. Not to mention that it's not intuitive with how structures normally work. According to individuals in the IRC channel, this is probably due to the implicit void in structs. Can someone shed some light on this?
Sep 02 2013
My current workaround is to use `Foo.tupleof.length == 0` to detect if a struct has size. But, as you can imagine, this is neither intuitive or optimal.
Sep 02 2013
On 9/3/13, Dylan Knutson <tcdknutson gmail.com> wrote:Take a look at this: http://dpaste.dzfl.pl/6bf578a3I suggest: ----- void sendPayload(Resp)(Resp response) { static if(Resp.sizeof) { pragma(msg, "has a size"); } else { pragma(msg, "has no size"); } } void main() { sendPayload(cast(void[0])[]); } ----- So try to use `void[0]` as a type. When you have such a type, you can initialize it with [], for example: ----- void[0][int] hash; void main() { hash[1] = []; assert(1 in hash); } -----
Sep 02 2013
On 9/2/2013 4:57 PM, Dylan Knutson wrote:Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:On 9/2/2013 4:57 PM, Dylan Knutson wrote:Why is that important, and why does D need it? In C, this might make some sense, however empty structs are much more useful in D, e.g. for metaprogramming.Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On 9/3/13 8:34, Vladimir Panteleev wrote:On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:struct Z {}; Z a, b; assert(&a != &b);On 9/2/2013 4:57 PM, Dylan Knutson wrote:Why is that important, and why does D need it? In C, this might make some sense, however empty structs are much more useful in D, e.g. for metaprogramming.Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On 9/3/13, Lionello Lunesu <lionello lunesu.remove.com> wrote:struct Z {}; Z a, b; assert(&a != &b);Since the structs are declared empty, their 1-byte values don't matter. So their addresses don't really matter either.
Sep 02 2013
On 9/3/13 10:59, Andrej Mitrovic wrote:On 9/3/13, Lionello Lunesu <lionello lunesu.remove.com> wrote:It has to do with the ol' 'identity vs equality'. In the example above, a and b are not identical ("do not refer to the same thing") and so their addresses should not be equal. The address of two 'named things' is the same if-and-only-if the names refer to the same thing. L.struct Z {}; Z a, b; assert(&a != &b);Since the structs are declared empty, their 1-byte values don't matter. So their addresses don't really matter either.
Sep 04 2013
On Tuesday, 3 September 2013 at 02:31:44 UTC, Lionello Lunesu wrote:On 9/3/13 8:34, Vladimir Panteleev wrote:Yes, but why is this important? If you declare Z as "alias int[0] Z", the assert passes, so why is this property needed for structs but not static arrays?On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:struct Z {}; Z a, b; assert(&a != &b);On 9/2/2013 4:57 PM, Dylan Knutson wrote:Why is that important, and why does D need it? In C, this might make some sense, however empty structs are much more useful in D, e.g. for metaprogramming.Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On Tuesday, 3 September 2013 at 03:08:34 UTC, Vladimir Panteleev wrote:On Tuesday, 3 September 2013 at 02:31:44 UTC, Lionello Lunesu wrote:alias int[0] Y; Y.sizeof == 0 // Bug? Y a; a.length == 0; // Correct. This is a bug IMO because the size of Y is 1 byte, not 0. struct Z{} Z.sizeof = 1; Z a,b; If I see code like this I expect a & b to have different addresses. But then I'm heavily influenced by C/C++. I'd prefer a different syntax, say: union struct Z{} or immutable struct Z{} either of these reflect that all instances will share the same memory location. G.On 9/3/13 8:34, Vladimir Panteleev wrote:Yes, but why is this important? If you declare Z as "alias int[0] Z", the assert passes, so why is this property needed for structs but not static arrays?On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:struct Z {}; Z a, b; assert(&a != &b);On 9/2/2013 4:57 PM, Dylan Knutson wrote:Why is that important, and why does D need it? In C, this might make some sense, however empty structs are much more useful in D, e.g. for metaprogramming.Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On Tuesday, 3 September 2013 at 03:57:09 UTC, growler wrote:If I see code like this I expect a & b to have different addresses.Why? What do you need that assumption for? What will break if the structs became 0-sized?
Sep 02 2013
On Tuesday, 3 September 2013 at 04:25:33 UTC, Vladimir Panteleev wrote:On Tuesday, 3 September 2013 at 03:57:09 UTC, growler wrote:There's no real reason, it's just a personal preference. As I said I'm heavily influenced by a C/C++ background and as such would prefer a different syntax.If I see code like this I expect a & b to have different addresses.Why? What do you need that assumption for? What will break if the structs became 0-sized?
Sep 02 2013
On 9/2/2013 5:34 PM, Vladimir Panteleev wrote:On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:There were huge debates about this back when the C standard was in development. I don't really want to start that up again :-), I don't remember all the pros and cons, suffice to say that with D's vaunted C compatibility I think it should behave the same way.On 9/2/2013 4:57 PM, Dylan Knutson wrote:Why is that important, and why does D need it? In C, this might make some sense, however empty structs are much more useful in D, e.g. for metaprogramming.Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On Tuesday, 3 September 2013 at 04:33:16 UTC, Walter Bright wrote:There were huge debates about this back when the C standard was in development. I don't really want to start that up again :-), I don't remember all the pros and cons, suffice to say that with D's vaunted C compatibility I think it should behave the same way.Fair enough. Was there any discussion on these forums about it? It sounds like an interesting topic of discussion, because I'm curious what the use cases are in D. Not to start a debate on it, but what compatibility with C is D is afforded by not having zero sized structs? It seems like D has abandoned a fair number of C warts, so it seems odd that this (to me, obscure one) one would stay.
Sep 02 2013
On 9/2/2013 9:39 PM, Dylan Knutson wrote:On Tuesday, 3 September 2013 at 04:33:16 UTC, Walter Bright wrote:Not following this aspect of C would result in silent and unexpected changes in behavior when interfacing D to C data structures, which D is supposed to be very good at.There were huge debates about this back when the C standard was in development. I don't really want to start that up again :-), I don't remember all the pros and cons, suffice to say that with D's vaunted C compatibility I think it should behave the same way.Fair enough. Was there any discussion on these forums about it? It sounds like an interesting topic of discussion, because I'm curious what the use cases are in D. Not to start a debate on it, but what compatibility with C is D is afforded by not having zero sized structs? It seems like D has abandoned a fair number of C warts, so it seems odd that this (to me, obscure one) one would stay.
Sep 02 2013
On Tuesday, 3 September 2013 at 05:51:36 UTC, Walter Bright wrote:Not following this aspect of C would result in silent and unexpected changes in behavior when interfacing D to C data structures, which D is supposed to be very good at.Fair enough. I'll guess stick with `SomeStruct.tupleof.length == 0` to determine if a struct has no members.
Sep 02 2013
On 03.09.2013 07:51, Walter Bright wrote:On 9/2/2013 9:39 PM, Dylan Knutson wrote:How about specifying extern(C) before each C structure? The majority of bindings already have "extern(C):" on top of module.On Tuesday, 3 September 2013 at 04:33:16 UTC, Walter Bright wrote:Not following this aspect of C would result in silent and unexpected changes in behavior when interfacing D to C data structures, which D is supposed to be very good at.There were huge debates about this back when the C standard was in development. I don't really want to start that up again :-), I don't remember all the pros and cons, suffice to say that with D's vaunted C compatibility I think it should behave the same way.Fair enough. Was there any discussion on these forums about it? It sounds like an interesting topic of discussion, because I'm curious what the use cases are in D. Not to start a debate on it, but what compatibility with C is D is afforded by not having zero sized structs? It seems like D has abandoned a fair number of C warts, so it seems odd that this (to me, obscure one) one would stay.
Sep 03 2013
On 9/3/2013 9:00 AM, Piotr Szturmaj wrote:How about specifying extern(C) before each C structure? The majority of bindings already have "extern(C):" on top of module.While we could do that, at what point does this become arcane complexity?
Sep 03 2013
On Tuesday, 3 September 2013 at 19:30:53 UTC, Walter Bright wrote:On 9/3/2013 9:00 AM, Piotr Szturmaj wrote:I think it depends how much metaprogramming could benefit in the language. Algebraic datatypes use zero sized structs in may places (see Rust, with Option(T) variants None and Some(T)), and I've heard of devs using structs as namespaces. In C, there was pretty much no metaprogramming to speak of, so semantic struct sizes just weren't a bit deal (as far as I can tell, that is). But, in D, metaprogramming is a ubiquitous feature, so I do think it's reasonable to consider some way of specifying zero sized structs in the language. I'd argue for it to be an opt-in feature though, so empty structs, by default, can't have a zero size. This keeps code backwards compatible. Perhaps something like `enum struct Foo;`, to indicate that it's just a compile-time used distinct type, and not a value? Just throwing that out there. I'm sure there is a better way to indicate that a type is just used as a type/namespace, without a value persay. When you say retain C compatibility, do you mean having C code which makes use of empty structs still be compile-able with the D compiler? Or D code inter-oping with external C libraries?How about specifying extern(C) before each C structure? The majority of bindings already have "extern(C):" on top of module.While we could do that, at what point does this become arcane complexity?
Sep 03 2013
On 9/3/2013 1:01 PM, Dylan Knutson wrote:Perhaps something like `enum struct Foo;`, to indicate that it's just a compile-time used distinct type, and not a value? Just throwing that out there. I'm sure there is a better way to indicate that a type is just used as a type/namespace, without a value persay.If you need a zero sized object in D, alias whatever[0] zeroSizeObject;When you say retain C compatibility, do you mean having C code which makes use of empty structs still be compile-able with the D compiler? Or D code inter-oping with external C libraries?Yes.
Sep 03 2013
On Tuesday, 3 September 2013 at 20:07:57 UTC, Walter Bright wrote:If you need a zero sized object in D, alias whatever[0] zeroSizeObject;I tried that, but unfortunately std.variant isn't compatible with zero sized types: ``` import std.variant; import std.stdio; import std.typecons; void main() { // This would be preferable, but Algebraic doens't like zero sized types //alias FirstType = void[0]; //alias SecondType = void[0]; // phobos\std\variant.d(165): Error: static assert (0u >= 4u) is false // phobos\std\variant.d(1149): instantiated from here: VariantN!(0u, void[0u], void[0u]) // Typedef!() wraps void[0] in a struct, which still has a size, and therefore // memory overhead, so we're back to square one. alias FirstType = Typedef!(void[0]); alias SecondType = Typedef!(void[0]); pragma(msg, FirstType.sizeof); // 1UL, darn alias Variants = Algebraic!(FirstType, SecondType); } ```
Sep 03 2013
On 9/3/13, Dylan Knutson <tcdknutson gmail.com> wrote:I tried that, but unfortunately std.variant isn't compatible with zero sized types:Please do file this as a bug: http://d.puremagic.com/issues/enter_bug.cgi?product=D If you don't have the time, we'll file it for you. Thanks!
Sep 03 2013
On Tuesday, 3 September 2013 at 20:42:47 UTC, Andrej Mitrovic wrote:On 9/3/13, Dylan Knutson <tcdknutson gmail.com> wrote:Reported. I didn't realize this wasn't the intended behavior of Variant. :-) http://d.puremagic.com/issues/show_bug.cgi?id=10958I tried that, but unfortunately std.variant isn't compatible with zero sized types:Please do file this as a bug: http://d.puremagic.com/issues/enter_bug.cgi?product=D If you don't have the time, we'll file it for you. Thanks!
Sep 03 2013
On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:On 9/2/2013 4:57 PM, Dylan Knutson wrote:So, because backwards compatibility is an important consideration, what type of code breakage might one expect if D was to implement zero-size structs?Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 02 2013
On 9/2/2013 9:28 PM, Dylan Knutson wrote:On Tuesday, 3 September 2013 at 00:05:04 UTC, Walter Bright wrote:Some background: http://stackoverflow.com/questions/7881487/zero-sized-struct http://stackoverflow.com/questions/10971651/zero-size-struct http://stackoverflow.com/questions/755305/empty-structure-in-c http://connect.microsoft.com/VisualStudio/feedback/details/355187/marshal-sizeof-returns-wrong-struct-size-for-empty-struct https://mail.elegosoft.com/pipermail/m3devel/2012-October/010196.htmlOn 9/2/2013 4:57 PM, Dylan Knutson wrote:So, because backwards compatibility is an important consideration, what type of code breakage might one expect if D was to implement zero-size structs?Can someone shed some light on this?It comes from C. This was done in C so that addresses of struct instances will always be unique.
Sep 03 2013
On 09/03/2013 12:35 PM, Walter Bright wrote:Some background:Ooh! This one has a very interesting excerpt: http://stackoverflow.com/a/10971748 "If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined." So the question is moot because empty struct has undefined behavior... in C... perhaps in D as well... Sweet! :) Ali
Sep 03 2013
On 9/3/2013 2:43 PM, Ali Çehreli wrote:On 09/03/2013 12:35 PM, Walter Bright wrote:In C++ it is defined.Some background:Ooh! This one has a very interesting excerpt: http://stackoverflow.com/a/10971748 "If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined." So the question is moot because empty struct has undefined behavior... in C... perhaps in D as well... Sweet! :)
Sep 03 2013