digitalmars.D - Suggestion: class/struct tuples preserve anonymous unions/structs
- Jarrett Billingsley (46/46) Feb 14 2007 If you write something like this:
- Frits van Bommel (79/98) Feb 15 2007 I don't think it's being "flattened out" by the type tuple mechanism, I
- Jarrett Billingsley (5/33) Feb 15 2007 I was kind of worried about that. Well we can hope..
- Frits van Bommel (6/9) Feb 15 2007 Something I just thought of: that code doesn't take typedefs into
- Jarrett Billingsley (4/13) Feb 15 2007 WAITWaitwaitwait. When the *hell* was .stringof added?
- Jarrett Billingsley (4/6) Feb 15 2007 I guess I missed the mini-conversation in the DMD 1.005 thread.. man! W...
- Frits van Bommel (4/13) Feb 15 2007 Yes it is :).
- Walter Bright (4/5) Feb 15 2007 This has nothing to do with tuples. Anonymous structs and unions are
- Frits van Bommel (7/14) Feb 15 2007 It's fairly obvious this is what's happening. And normally this wouldn't...
- Sean Kelly (5/20) Feb 15 2007 I think as long as .offsetof can be obtained for the values then
- Frits van Bommel (5/25) Feb 15 2007 Yeah, you can figure it out like this, but I do think exposing anonymous...
If you write something like this: struct S { int x; union U { int a; int b; } U u; } And print out its field types: foreach(T; FieldTypeTuple!(S)) writefln(typeid(T)); It will print out int test.S.U But if you make the union anonymous: struct S { int x; union { int a; int b; } } The output becomes: int int int The anonymous union is getting "flattened out" by the type tuple mechanism. This messes up some automation features. For example I'm trying to write a simple "Serialize" function which can serialize entire structs. But unions can't be automatically serialized, since the Serialize function has no idea which member of the union is currently "valid." So I have error checking to disallow serializing unions, but since the .tupleof facility flattens out anonymous unions, it can't check for errors (and therefore I don't know that there's a problem until I write the struct out to a file and end up with a bunch of invalid members, since they came from the anonymous union). I'm not sure how anonymous unions and structs are handled by the compiler. If they are created as "secret" types, would it then be possible for the above struct with the anonymous union to consist of: int test.S.__UNION0 or something like that?
Feb 14 2007
Jarrett Billingsley wrote:The anonymous union is getting "flattened out" by the type tuple mechanism. This messes up some automation features. For example I'm trying to write a simple "Serialize" function which can serialize entire structs. But unions can't be automatically serialized, since the Serialize function has no idea which member of the union is currently "valid." So I have error checking to disallow serializing unions, but since the .tupleof facility flattens out anonymous unions, it can't check for errors (and therefore I don't know that there's a problem until I write the struct out to a file and end up with a bunch of invalid members, since they came from the anonymous union). I'm not sure how anonymous unions and structs are handled by the compiler. If they are created as "secret" types, would it then be possible for the above struct with the anonymous union to consist of: int test.S.__UNION0 or something like that?I don't think it's being "flattened out" by the type tuple mechanism, I think it happens *before* that. They're not created as secret types, they just seem to use different rules for offset calculation. I'm not really sure whether or not this is a bug in the compiler, but it happens. The following template can be used to check for unions (anonymous and named) and generate compile errors when it finds any: ----- /** static asserts when T is a union or contains unions. * Note: the 'Idx' parameter should be left at the default by * code outside the template. */ template validate(T, size_t Idx = 0) { static assert(!is(T == union), T.stringof ~ " is a union itself!"); static assert(!is(typeof(T.tupleof)[Idx] == union), "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " is a union"); static if (Idx + 1 < T.tupleof.length) { // check overlap caused by anonymous union members static assert(T.tupleof[Idx].offsetof + T.tupleof[Idx].sizeof <= T.tupleof[Idx + 1].offsetof, "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " overlaps the next member"); // and check the other members mixin validate!(T, Idx + 1); } static if (Idx < T.tupleof.length) { // Recurse into member structs static if (is(typeof(T.tupleof)[Idx] == struct)) mixin validate!(typeof(T.tupleof)[Idx]); // uncomment these lines to recurse into member class references as well: //else static if (is(typeof(T.tupleof)[Idx] == class)) // mixin validate!(typeof(T.tupleof)[Idx]); } } // // Some test code: // struct SAnonUnion { int x; union { int a; int b; } } struct SUnion { int x; union U { int a; int b; } U u; } struct SValid { int x; int a; int b; } class Class { SUnion u; } struct SNested { Class u; } void main() { //mixin validate!(SAnonUnion); // error :) //mixin validate!(SUnion); // error :) mixin validate!(SNested); // error if class references are followed, or 'Class' is changed to a struct mixin validate!(SValid); } ----- (You may have to correct some line wrapping before it'll compile)
Feb 15 2007
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:er1cc3$3sr$1 digitalmars.com...I don't think it's being "flattened out" by the type tuple mechanism, I think it happens *before* that. They're not created as secret types, they just seem to use different rules for offset calculation. I'm not really sure whether or not this is a bug in the compiler, but it happens.I was kind of worried about that. Well we can hope..template validate(T, size_t Idx = 0) { static assert(!is(T == union), T.stringof ~ " is a union itself!"); static assert(!is(typeof(T.tupleof)[Idx] == union), "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " is a union"); static if (Idx + 1 < T.tupleof.length) { // check overlap caused by anonymous union members static assert(T.tupleof[Idx].offsetof + T.tupleof[Idx].sizeof <= T.tupleof[Idx + 1].offsetof, "Member " ~ Idx.stringof ~ " of " ~ T.stringof ~ " overlaps the next member"); // and check the other members mixin validate!(T, Idx + 1); } static if (Idx < T.tupleof.length) { // Recurse into member structs static if (is(typeof(T.tupleof)[Idx] == struct)) mixin validate!(typeof(T.tupleof)[Idx]); // uncomment these lines to recurse into member class references as well: //else static if (is(typeof(T.tupleof)[Idx] == class)) // mixin validate!(typeof(T.tupleof)[Idx]); } }Thanks for this :) I was thinking it might be possible to check the .offsetofs.
Feb 15 2007
Jarrett Billingsley wrote: [snip code]Thanks for this :) I was thinking it might be possible to check the .offsetofs.Something I just thought of: that code doesn't take typedefs into account. That loophole can be closed by using is(T Base == typedef) and inspecting Base recursively if it evaluates to true. Implementing this is left as an exercise to the reader ;).
Feb 15 2007
"Frits van Bommel" <fvbommel REMwOVExCAPSs.nl> wrote in message news:er1ost$mae$1 digitalmars.com...Jarrett Billingsley wrote: [snip code]WAITWaitwaitwait. When the *hell* was .stringof added? :DThanks for this :) I was thinking it might be possible to check the .offsetofs.Something I just thought of: that code doesn't take typedefs into account. That loophole can be closed by using is(T Base == typedef) and inspecting Base recursively if it evaluates to true. Implementing this is left as an exercise to the reader ;).
Feb 15 2007
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message news:er1s3r$qqa$1 digitalmars.com...WAITWaitwaitwait. When the *hell* was .stringof added? :DI guess I missed the mini-conversation in the DMD 1.005 thread.. man! What a cool feature :)
Feb 15 2007
Jarrett Billingsley wrote:"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message news:er1s3r$qqa$1 digitalmars.com...Yes it is :). It's not really essential here though, I just used it to provide more readable error messages for assertion failures...WAITWaitwaitwait. When the *hell* was .stringof added? :DI guess I missed the mini-conversation in the DMD 1.005 thread.. man! What a cool feature :)
Feb 15 2007
Jarrett Billingsley wrote:I'm not sure how anonymous unions and structs are handled by the compiler.This has nothing to do with tuples. Anonymous structs and unions are used for layout only, the members are 'promoted' into the enclosing aggregate.
Feb 15 2007
Walter Bright wrote:Jarrett Billingsley wrote:It's fairly obvious this is what's happening. And normally this wouldn't matter as you wouldn't be able see the difference, but because of .tupleof this is now detectable. I think the real question here is: while this may be what *is* happening, is this also what *should* happen? (i.e. "Is this a bug?") I can't find anything specifying this behavior in the spec...I'm not sure how anonymous unions and structs are handled by the compiler.This has nothing to do with tuples. Anonymous structs and unions are used for layout only, the members are 'promoted' into the enclosing aggregate.
Feb 15 2007
Frits van Bommel wrote:Walter Bright wrote:I think as long as .offsetof can be obtained for the values then everything should be fine. You know members are part of a union when their .offsetof is the same. SeanJarrett Billingsley wrote:It's fairly obvious this is what's happening. And normally this wouldn't matter as you wouldn't be able see the difference, but because of ..tupleof this is now detectable. I think the real question here is: while this may be what *is* happening, is this also what *should* happen? (i.e. "Is this a bug?") I can't find anything specifying this behavior in the spec...I'm not sure how anonymous unions and structs are handled by the compiler.This has nothing to do with tuples. Anonymous structs and unions are used for layout only, the members are 'promoted' into the enclosing aggregate.
Feb 15 2007
Sean Kelly wrote:Frits van Bommel wrote:Yeah, you can figure it out like this, but I do think exposing anonymous structs and unions as actual struct an union members would lead to cleaner code for some cases. Even if this only happens when it's nested in an aggregate of the other type (or a union in a class).Walter Bright wrote:I think as long as .offsetof can be obtained for the values then everything should be fine. You know members are part of a union when their .offsetof is the same.Jarrett Billingsley wrote:It's fairly obvious this is what's happening. And normally this wouldn't matter as you wouldn't be able see the difference, but because of ..tupleof this is now detectable. I think the real question here is: while this may be what *is* happening, is this also what *should* happen? (i.e. "Is this a bug?") I can't find anything specifying this behavior in the spec...I'm not sure how anonymous unions and structs are handled by the compiler.This has nothing to do with tuples. Anonymous structs and unions are used for layout only, the members are 'promoted' into the enclosing aggregate.
Feb 15 2007