www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - The great inapplicable attribute debate

reply Stewart Gordon <smjg_1998 yahoo.com> writes:
It's cropped up on a number of occasions.  And again in the comments on
http://d.puremagic.com/issues/show_bug.cgi?id=2830
http://d.puremagic.com/issues/show_bug.cgi?id=1441
which are essentially the same as each other.  The basic matter of 
debate is: If an attribute is applied to something to which it is not 
applicable, should it be an error, silently ignored or what?

There are a number of cases to consider:

(a) Attributes that state what is already implied by the context.  For 
example, module-level functions are effectively both static and final.

(b) Attributes that don't make sense in the context.  For example, 
trying to apply scope to a function.

(c) Attributes that make sense in the context but are nonetheless not 
actually applied.  The issue brought up in the above bug reports is an 
example - actual compiler behaviour even _contradicts_ the fact that a 
protection attribute has been specified.

One recent comment referred to inapplicable attributes generally as 
"'pointless' attributes".  This may be a valid label for (a), but 
certainly not (b) or (c).


At the moment, the problem seems to be that the compiler is silently 
ignoring many cases of (a), (b) and (c) alike.  Some people argue that 
the spec doesn't forbid such use of inapplicable attributes explicitly, 
and so the compiler's treatment of these cannot be called a bug.

I argue that this isn't right.  Nothing I've managed to find in the spec 
states or implies that such obviously wrong code is allowed.  So, by 
applying common sense, one would conclude that it isn't allowed.


Perhaps what complicates matters further is that D has three ways of 
specifying attributes:

(i) as part of the declaration itself
(ii) in a block delimited by { }
(iii) with a colon to apply to everything that follows until the end of 
the scope

It would be annoying to have to avoid (iii) just because you want to 
declare something of a kind to which the attribute is inapplicable later 
in the file.  This may also apply to some degree to (ii), but any use of 
an inapplicable attribute (at least of case (b) or (c)) by (i) is bound 
to be a mistake.

There are also attributes, such as align and (I think) extern, for which 
applying to a compound type is equivalent to applying to all of its 
members.  This should be allowed wherever it makes sense to the context, 
since it would be annoying (for example) to be prevented from declaring 
an alignment on a struct as a whole just because it contains functions.


Basically, what we need to do is:

- Eradicate all cases of (c), fixing it so that the attribute actually 
works in such cases.
- Make sure all cases of (b) generate a compile error when used by (i).
- Define some clear rules on when an attribute may be used by (ii) or 
(iii) if it is inapplicable to some of the entities to which the 
programmer has tried to apply it.


Comments?

Stewart.
Apr 12 2009
next sibling parent reply BCS <none anon.com> writes:
Hello Stewart,

 Perhaps what complicates matters further is that D has three ways of
 specifying attributes:
 
 (i) as part of the declaration itself

I more or less only use this.
 (ii) in a block delimited by { }

If I remembered that this one even exists, I might use it.
 (iii) with a colon to apply to everything that follows until the end
 of
 the scope

I'd be just tickled if this one were just dropped. Just my $0.02 because that might make things less complex.
Apr 12 2009
next sibling parent "Nick Sabalausky" <a a.a> writes:
"BCS" <none anon.com> wrote in message 
news:a6268ff4a7a8cb89c641dc84ac news.digitalmars.com...
 Hello Stewart,

 Perhaps what complicates matters further is that D has three ways of
 specifying attributes:

 (i) as part of the declaration itself

I more or less only use this.
 (ii) in a block delimited by { }

If I remembered that this one even exists, I might use it.
 (iii) with a colon to apply to everything that follows until the end
 of
 the scope

I'd be just tickled if this one were just dropped. Just my $0.02 because that might make things less complex.

I'm kind of on the fence about whether (ii) or (iii) should be allowed. I haven't used (iii) since I was using C/C++ regularly (ie, almost 10 years ago). But I think the only real reason I switched from (iii) to (i) was because of the time I spent with Java and C#. I would never want to get rid of (i), but I keep debating with myself about occasional usage of (ii) or (iii).
Apr 12 2009
prev sibling parent reply grauzone <none example.net> writes:
BCS wrote:
 Hello Stewart,
 
 Perhaps what complicates matters further is that D has three ways of
 specifying attributes:

 (i) as part of the declaration itself

I more or less only use this.
 (ii) in a block delimited by { }

If I remembered that this one even exists, I might use it.
 (iii) with a colon to apply to everything that follows until the end
 of
 the scope

I'd be just tickled if this one were just dropped. Just my $0.02 because that might make things less complex.

I use all three all the time. It's a nice mini feature of D. No reason to remove it. And if you want to remove complexity, start with the bigger chunks of the D language.
Apr 12 2009
parent BCS <none anon.com> writes:
Hello grauzone,

 BCS wrote:
 
 Just my $0.02 because that might make things less complex.
 

the D language.

complexity re the OP's point, not just in general. if only (i) is allowed then there isn't (much of) a case for allowing inapplicable attribute (IMHO).
Apr 12 2009
prev sibling next sibling parent "Nick Sabalausky" <a a.a> writes:
"Stewart Gordon" <smjg_1998 yahoo.com> wrote in message 
news:grtr90$1hlh$1 digitalmars.com...
 It's cropped up on a number of occasions.  And again in the comments on
 http://d.puremagic.com/issues/show_bug.cgi?id=2830
 http://d.puremagic.com/issues/show_bug.cgi?id=1441
 which are essentially the same as each other.  The basic matter of debate 
 is: If an attribute is applied to something to which it is not applicable, 
 should it be an error, silently ignored or what?

 There are a number of cases to consider:

 (a) Attributes that state what is already implied by the context.  For 
 example, module-level functions are effectively both static and final.

 (b) Attributes that don't make sense in the context.  For example, trying 
 to apply scope to a function.

 (c) Attributes that make sense in the context but are nonetheless not 
 actually applied.  The issue brought up in the above bug reports is an 
 example - actual compiler behaviour even _contradicts_ the fact that a 
 protection attribute has been specified.

[snip]

 Perhaps what complicates matters further is that D has three ways of 
 specifying attributes:

 (i) as part of the declaration itself
 (ii) in a block delimited by { }
 (iii) with a colon to apply to everything that follows until the end of 
 the scope

[snip]

 Basically, what we need to do is:

 - Eradicate all cases of (c), fixing it so that the attribute actually 
 works in such cases.
 - Make sure all cases of (b) generate a compile error when used by (i).
 - Define some clear rules on when an attribute may be used by (ii) or 
 (iii) if it is inapplicable to some of the entities to which the 
 programmer has tried to apply it.

Absolutely. I think it boils down to this: If something seems to work, it should work as expected. Things should either just "work" or "not work". _Never_ "it works, but does something completely different". I think this ticket I filed might also be another case of the same issue: http://d.puremagic.com/issues/show_bug.cgi?id=2775 I've never even looked to see if the language definition explicitly allows/forbids/doesn't-address using "private" on templates/structs/classes/unions. But for such a basic and conceptually simple language feature, I shouldn't even need to. Don't force me to be a language lawyer to use such simple things properly: If I stick "private" in front of something, and the compiler *accepts* it, it should "just f*^&*%^* work". If for some bizarre reason private templates/structs/classes/unions aren't supposed to be allowed (which I *really* hope is not the case), then dagnabbit, the compiler needs to speak up. After all, it is the role of the compiler to raise an error when the programmer tries to do something that isn't allowed, and not to just silently make up some alternative behavior (if I wanted to put up with that kind of "principle of maximum silent surprises" crap I'd use a scripting language). Until now I just assumed these were a compiler bugs, but if this "let's let the programmer *think* this is working the way they intended" behavior is intentional just for the sake of Stewart's (ii) and (iii), well then that's terrible and absolutely needs to change.
Apr 12 2009
prev sibling parent reply Kagamin <spam here.lot> writes:
Stewart Gordon Wrote:

 At the moment, the problem seems to be that the compiler is silently 
 ignoring many cases of (a), (b) and (c) alike.  Some people argue that 
 the spec doesn't forbid such use of inapplicable attributes explicitly, 
 and so the compiler's treatment of these cannot be called a bug.
 
 I argue that this isn't right.  Nothing I've managed to find in the spec 
 states or implies that such obviously wrong code is allowed.  So, by 
 applying common sense, one would conclude that it isn't allowed.

Such mood was always in the spec: "AlignAttribute is ignored when applied to declarations that are not structs or struct members".
Apr 13 2009
next sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Kagamin wrote:
 Stewart Gordon Wrote:
 
 At the moment, the problem seems to be that the compiler is silently 
 ignoring many cases of (a), (b) and (c) alike.  Some people argue that 
 the spec doesn't forbid such use of inapplicable attributes explicitly, 
 and so the compiler's treatment of these cannot be called a bug.

 I argue that this isn't right.  Nothing I've managed to find in the spec 
 states or implies that such obviously wrong code is allowed.  So, by 
 applying common sense, one would conclude that it isn't allowed.

Such mood was always in the spec: "AlignAttribute is ignored when applied to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members? And it won't change the alignment of unions if applied to union members (by changing the maximum alignment of the members)?
Apr 13 2009
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Frits van Bommel wrote:
 Kagamin wrote:

 Such mood was always in the spec: "AlignAttribute is ignored when 
 applied to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members?

http://www.digitalmars.com/d/1.0/class.html "The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes."
 And it 
 won't change the alignment of unions if applied to union members (by 
 changing the maximum alignment of the members)?

I'm not sure what you mean.... But there seem to be a few issues with the behaviour of align. I'll have to investigate.... Stewart.
Apr 13 2009
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Stewart Gordon wrote:
 Frits van Bommel wrote:
 Kagamin wrote:

 Such mood was always in the spec: "AlignAttribute is ignored when 
 applied to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members?

http://www.digitalmars.com/d/1.0/class.html "The D compiler is free to rearrange the order of fields in a class to optimally pack them in an implementation-defined manner. Consider the fields much like the local variables in a function - the compiler assigns some to registers and shuffles others around all to get the optimal stack frame layout. This frees the code designer to organize the fields in a manner that makes the code more readable rather than being forced to organize it according to machine optimization rules. Explicit control of field layout is provided by struct/union types, not classes."

Right, forgot about that bit. Probably because AFAIK no D compiler actually reorganizes them... (How does this combine with the "D ABI" anyway? I know binary compatibility between the different compilers is a bit of a pipe dream at the moment, but the only way that could work would be to standardize any and all shuffling of class fields...)
 And it won't change the alignment of unions if applied to union 
 members (by changing the maximum alignment of the members)?

I'm not sure what you mean....

Unions are normally aligned to the maximum alignment for any member. Now consider: union U { align(1) void* p; ubyte[size_t.sizeof] bytes; } union U2 { align(4) ubyte[12] data; char[12] str; } What are U.alignof and U2.alignof? According to that piece of the spec, those align() attributes should be useless. However, according to DMD[1] U.alignof is 1, and without the attribute it's 4. U2 on the other hand is align(1) regardless of attribute. It seems DMD disagrees with the spec here. Same goes for GDC, except U.alignof is 8 without the attribute instead of 4 because I'm using a 64-bit version. LDC seems to agree with the spec (it ignores the aligns), but that may just be because it doesn't fully support align() in the first place... [1]: 1.042 on Linux: void main() { printf("%d %d\n", cast(int)U.alignof, cast(int)U2.alignof); }
Apr 13 2009
next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Frits van Bommel wrote:
 Stewart Gordon wrote:

[rearrangement of class fields]
 
 Right, forgot about that bit. Probably because AFAIK no D compiler 
 actually reorganizes them...
 
 (How does this combine with the "D ABI" anyway? I know binary 
 compatibility between the different compilers is a bit of a pipe dream 
 at the moment, but the only way that could work would be to standardize 
 any and all shuffling of class fields...)

Good question. But AAs are another thing that's implementation defined at the moment. <snip>
 Unions are normally aligned to the maximum alignment for any member. Now 
 consider:
 
 union U {
     align(1) void* p;
     ubyte[size_t.sizeof] bytes;
 }
 union U2 {
     align(4) ubyte[12] data;
     char[12] str;
 }
 What are U.alignof and U2.alignof?
 
 According to that piece of the spec, those align() attributes should be 
 useless.
 However, according to DMD[1] U.alignof is 1, and without the attribute 
 it's 4.
 U2 on the other hand is align(1) regardless of attribute.

Sounds like a bug. Surely, align isn't applicable to unions at all. IINM the members of a union, by design, start at the same offset. An anonymous struct within a union, or an anonymous union within a struct, might have alignment - in either case, it would be in relation to the struct. Stewart.
Apr 13 2009
parent reply Don <nospam nospam.com> writes:
Stewart Gordon wrote:
 Unions are normally aligned to the maximum alignment for any member. 
 Now consider:

 union U {
     align(1) void* p;
     ubyte[size_t.sizeof] bytes;
 }
 union U2 {
     align(4) ubyte[12] data;
     char[12] str;
 }
 What are U.alignof and U2.alignof?

 According to that piece of the spec, those align() attributes should 
 be useless.
 However, according to DMD[1] U.alignof is 1, and without the attribute 
 it's 4.
 U2 on the other hand is align(1) regardless of attribute.

Sounds like a bug.

Definitely.
 
 Surely, align isn't applicable to unions at all.  IINM the members of a 
 union, by design, start at the same offset.

Not so, the alignment of each member should be respected. Most obviously, a union U consisting of a single member x should have U.alignof == x.alignof. An anonymous struct within
 a union, or an anonymous union within a struct, might have alignment - 
 in either case, it would be in relation to the struct.

 
 Stewart.

Apr 14 2009
next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Don wrote:
 Stewart Gordon wrote:

 Surely, align isn't applicable to unions at all.  IINM the members of 
 a union, by design, start at the same offset.

Not so, the alignment of each member should be respected.

But the offset of a union member is always zero. So what would this do?
 Most obviously, a union U consisting of a single member x should have
 U.alignof == x.alignof.

Yes, by propagating the union's alignment (relative to the containing struct) to the member. Stewart.
Apr 14 2009
parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:

 Surely, align isn't applicable to unions at all.  IINM the members of 
 a union, by design, start at the same offset.

Not so, the alignment of each member should be respected.

But the offset of a union member is always zero. So what would this do?

It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.
 Most obviously, a union U consisting of a single member x should have
 U.alignof == x.alignof.

Yes, by propagating the union's alignment (relative to the containing struct) to the member.

But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.
Apr 14 2009
next sibling parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Frits van Bommel wrote:
 Stewart Gordon wrote:

 But the offset of a union member is always zero.  So what would this do?

It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.

But alignment of a member within a structure and alignment of the whole structure relative to an outer one are two distinct concepts. What sense is there in being able to use one to control the other?
 Most obviously, a union U consisting of a single member x should have
 U.alignof == x.alignof.

Yes, by propagating the union's alignment (relative to the containing struct) to the member.

But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.

That's only because you want to be able to attach alignments to individual members of a union. And I still don't know why. If you want a union to have a certain alignment relative to a struct in which it's contained, in what cases is it not sufficient to put the align attribute on the union's instance in the struct? Stewart.
Apr 14 2009
parent reply Don <nospam nospam.com> writes:
Stewart Gordon wrote:
 Frits van Bommel wrote:
 Stewart Gordon wrote:

 But the offset of a union member is always zero.  So what would this do?

It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.

But alignment of a member within a structure and alignment of the whole structure relative to an outer one are two distinct concepts. What sense is there in being able to use one to control the other?
 Most obviously, a union U consisting of a single member x should have
 U.alignof == x.alignof.

Yes, by propagating the union's alignment (relative to the containing struct) to the member.

But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.

That's only because you want to be able to attach alignments to individual members of a union. And I still don't know why.

I'm not sure why you think unions are so different to structs. They are identical in most respects -- including requirements for alignment of members.
 
 If you want a union to have a certain alignment relative to a struct in 
 which it's contained, in what cases is it not sufficient to put the 
 align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.
Apr 14 2009
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Don wrote:
 Stewart Gordon wrote:

 That's only because you want to be able to attach alignments to 
 individual members of a union.  And I still don't know why.

I'm not sure why you think unions are so different to structs. They are identical in most respects -- including requirements for alignment of members.

I still don't know what you mean.
 If you want a union to have a certain alignment relative to a struct 
 in which it's contained, in what cases is it not sufficient to put the 
 align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don't know what member alignment that struct requires. The person who creates the struct, OTOH, does know. So why are you trying to do that person's job? Stewart.
Apr 14 2009
next sibling parent Christopher Wright <dhasenan gmail.com> writes:
Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:

 That's only because you want to be able to attach alignments to 
 individual members of a union.  And I still don't know why.

I'm not sure why you think unions are so different to structs. They are identical in most respects -- including requirements for alignment of members.

I still don't know what you mean.
 If you want a union to have a certain alignment relative to a struct 
 in which it's contained, in what cases is it not sufficient to put 
 the align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don't know what member alignment that struct requires. The person who creates the struct, OTOH, does know. So why are you trying to do that person's job? Stewart.

You know ahead of time that you're going to use this union everywhere and that it should have proper alignment. If you still want to put the align attribute everywhere it's used instead, allow me to shoot you. Granted, you can replace your named union with a struct of the same name containing an anonymous union, and put the align attribute on that. That wouldn't be too odious (as long as the language specification mentioned the workaround), but since you already have align for unions, why bother changing it?
Apr 14 2009
prev sibling parent reply Don <nospam nospam.com> writes:
Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:

 That's only because you want to be able to attach alignments to 
 individual members of a union.  And I still don't know why.

I'm not sure why you think unions are so different to structs. They are identical in most respects -- including requirements for alignment of members.

I still don't know what you mean.

You're acting as if there's a big difference between unions and structs, and there isn't. Read the spec, the only differences are at construction, and struct literals.
 If you want a union to have a certain alignment relative to a struct 
 in which it's contained, in what cases is it not sufficient to put 
 the align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don't know what member alignment that struct requires.

Yes you do. The union doesn't control the alignment of the surrounding struct. It only controls the alignment of itself inside that struct. The person who creates
 the struct, OTOH, does know.  

They do NOT know. Not without probing every member in the union. So why are you trying to do that person's
 job?

No, you know what alignment the member requires. By the way, there doesn't even need to be a surrounding struct! An instance of the union on the stack may itself need to be aligned. And you can even create a bare union on the heap.
Apr 15 2009
parent reply Stewart Gordon <smjg_1998 yahoo.com> writes:
Don wrote:
 Stewart Gordon wrote:
 Don wrote:


 I'm not sure why you think unions are so different to structs. They 
 are identical in most respects -- including requirements for 
 alignment of members.

I still don't know what you mean.

You're acting as if there's a big difference between unions and structs, and there isn't. Read the spec, the only differences are at construction, and struct literals.

No, you have to add to that the differences inherited from C. Moreover, what difference could possibly be bigger than that between the basic essence of structs and the basic essence of unions? http://www.digitalmars.com/d/1.0/struct.html "They work like they do in C, with the following exceptions:" It's true that "alignment can be explicitly specified" is in there. But I'm not sure that Walter really meant it to apply to unions as well as structs. Especially given that it makes no comment (that I've found) on what align is meant to do in a union. Moreover, http://www.digitalmars.com/d/1.0/attribute.html#align "Specifies the alignment of struct members."
 If you want a union to have a certain alignment relative to a struct 
 in which it's contained, in what cases is it not sufficient to put 
 the align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don't know what member alignment that struct requires.

Yes you do. The union doesn't control the alignment of the surrounding struct. It only controls the alignment of itself inside that struct.

I thought that was meant to be controlled by an align applied to the union instance as a member of the struct, rather than by an align applied to the union itself. Only in the case of anonymous unions are they one and the same.
 The person who creates the struct, OTOH, does know.

They do NOT know. Not without probing every member in the union.

?? ISTM all they really need to know is the overall size of the union, which is equal to the size of the union's largest member (which is easy to find out).
 So why are you trying to do that person's
 job?

No, you know what alignment the member requires.

What are the cases in which a member _requires_ a certain alignment? OK, so there's one case: pointers in order to make sure the GC works properly. But this is absolute alignment. Maybe it's just me, but given that talk of alignment is nearly always in relation to structs, I'd made it out to be talking about relative alignment. Maybe the spec just needs to be clearer.... Stewart.
Apr 15 2009
parent Don <nospam nospam.com> writes:
Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:
 Don wrote:


 I'm not sure why you think unions are so different to structs. They 
 are identical in most respects -- including requirements for 
 alignment of members.

I still don't know what you mean.

You're acting as if there's a big difference between unions and structs, and there isn't. Read the spec, the only differences are at construction, and struct literals.

No, you have to add to that the differences inherited from C. Moreover, what difference could possibly be bigger than that between the basic essence of structs and the basic essence of unions?

In the compiler, struct and union share almost all of their code. Basically, a union is just a struct where all the elements are on top of each other. Which is a tiny difference compared (say) to the difference between structs and classes. For example, this works: union foo(T) { public: static int bar(int x) { return x*2; } } void main() { assert (foo!(int).bar(7)==14); }
 
 http://www.digitalmars.com/d/1.0/struct.html
 "They work like they do in C, with the following exceptions:"
 
 It's true that "alignment can be explicitly specified" is in there.  But 
 I'm not sure that Walter really meant it to apply to unions as well as 
 structs.  Especially given that it makes no comment (that I've found) on 
 what align is meant to do in a union. 

In a struct, align(4) int X; means, pad with zero bytes until the address you're up to is a multiple of 4, then put the int at that address. The address for the next element is the first byte past the int. In a union, align(4) int X; means, pad with zero bytes until the address you're up to is a multiple of 4, then put the int at that address. The address for the next element is the first byte of the union. Moreover,
 
 http://www.digitalmars.com/d/1.0/attribute.html#align
 "Specifies the alignment of struct members."
 
 If you want a union to have a certain alignment relative to a 
 struct in which it's contained, in what cases is it not sufficient 
 to put the align attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The union may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don't know what member alignment that struct requires.

Yes you do. The union doesn't control the alignment of the surrounding struct. It only controls the alignment of itself inside that struct.

I thought that was meant to be controlled by an align applied to the union instance as a member of the struct, rather than by an align applied to the union itself. Only in the case of anonymous unions are they one and the same.
 The person who creates the struct, OTOH, does know.

They do NOT know. Not without probing every member in the union.

?? ISTM all they really need to know is the overall size of the union, which is equal to the size of the union's largest member (which is easy to find out).
 So why are you trying to do that person's
 job?

No, you know what alignment the member requires.

What are the cases in which a member _requires_ a certain alignment?

Static arrays, eg float[4]. Must be aligned if you want to use the movaps instruction (which is 4X faster than the unaligned instruction). Alignment requirements are rare, even for structs.
 
 OK, so there's one case: pointers in order to make sure the GC works 
 properly.  But this is absolute alignment.  Maybe it's just me, but 
 given that talk of alignment is nearly always in relation to structs, 
 I'd made it out to be talking about relative alignment.  Maybe the spec 
 just needs to be clearer....
 
 Stewart.

Probably. Unions tend to get forgotten.
Apr 16 2009
prev sibling parent reply Christopher Wright <dhasenan gmail.com> writes:
Frits van Bommel wrote:
 Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:

 Surely, align isn't applicable to unions at all.  IINM the members 
 of a union, by design, start at the same offset.

Not so, the alignment of each member should be respected.

But the offset of a union member is always zero. So what would this do?

It should make sure the union is aligned appropriately in a containing struct, meaning U.alignof >= M.alignof for all members M. Specifying per-member alignment allows you to change that member's effect on the union's alignment.
 Most obviously, a union U consisting of a single member x should have
 U.alignof == x.alignof.

Yes, by propagating the union's alignment (relative to the containing struct) to the member.

But the union's alignment needs to be sufficient for all members, so it depends on the maximum alignment of all members.

Or the least common multiple, assuming that align accepts arguments that are not powers of 2.
Apr 14 2009
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Christopher Wright wrote:
 Frits van Bommel wrote:
 But the union's alignment needs to be sufficient for all members, so 
 it depends on the maximum alignment of all members.

Or the least common multiple, assuming that align accepts arguments that are not powers of 2.

I have never seen "alignment" used to describe addresses at a multiple of anything but a power of two. In fact, common object file formats (That I know of: ELF and LLVM bitcode) enforce this by only allowing alignments to be specified as powers of two. ELF does this by storing the log of the alignment instead of the alignment itself; LLVM currently encodes the full value for backward compatibility but asserts if this isn't a power of two (or zero) and IIRC they plan to switch to log-storage for LLVM 3.0 if and when it comes out.
Apr 14 2009
prev sibling parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Thu, Apr 16, 2009 at 12:34 PM, Don <nospam nospam.com> wrote:
 Stewart Gordon wrote:
 Don wrote:
 Stewart Gordon wrote:
 Don wrote:


<snip>
 I'm not sure why you think unions are so different to structs. They a=





 identical in most respects -- including requirements for alignment of
 members.

I still don't know what you mean.

You're acting as if there's a big difference between unions and structs=



 and there isn't. Read the spec, the only differences are at constructio=



 and struct literals.

No, you have to add to that the differences inherited from C. =C2=A0More=


 what difference could possibly be bigger than that between the basic
 essence of structs and the basic essence of unions?

In the compiler, struct and union share almost all of their code. Basically, a union is just a struct where all the elements are on top of each other. Which is a tiny difference compared (say) to the difference between structs and classes. For example, this works: union foo(T) { public: =C2=A0 static int bar(int x) { return x*2; } } void main() { =C2=A0assert (foo!(int).bar(7)=3D=3D14); }
 http://www.digitalmars.com/d/1.0/struct.html
 "They work like they do in C, with the following exceptions:"

 It's true that "alignment can be explicitly specified" is in there. =C2=


 I'm not sure that Walter really meant it to apply to unions as well as
 structs. =C2=A0Especially given that it makes no comment (that I've foun=


 what align is meant to do in a union.

In a struct, align(4) int X; means, pad with zero bytes until the address you're up to is a multiple of 4, then put the int at that address. The address for the next element is the first byte past the int. In a union, align(4) int X; means, pad with zero bytes until the address you're up to is a multiple of 4, then put the int at that address. =C2=A0=

 address for the next element is the first byte of the union.

 =C2=A0Moreover,
 http://www.digitalmars.com/d/1.0/attribute.html#align
 "Specifies the alignment of struct members."

 If you want a union to have a certain alignment relative to a struct
 in which it's contained, in what cases is it not sufficient to put t=






 attribute on the union's instance in the struct?

In cases where you don't know what the containing struct is. The unio=





 may just be a type returned from a template, for example.

If you don't know what the containing struct is, you probably also don=




 know what member alignment that struct requires.

Yes you do. The union doesn't control the alignment of the surrounding struct. It only controls the alignment of itself inside that struct.

I thought that was meant to be controlled by an align applied to the uni=


 instance as a member of the struct, rather than by an align applied to t=


 union itself. =C2=A0Only in the case of anonymous unions are they one an=


 same.

 The person who creates the struct, OTOH, does know.

They do NOT know. Not without probing every member in the union.

?? ISTM all they really need to know is the overall size of the union, which is equal to the size of the union's largest member (which is easy =


 find out).

 So why are you trying to do that person's
 job?

No, you know what alignment the member requires.

<snip> What are the cases in which a member _requires_ a certain alignment?

Static arrays, eg float[4]. Must be aligned if you want to use the movaps instruction (which is 4X faster than the unaligned instruction).

So now we just need align(N) for the storage as well as field offsets, to actually make that useful.
 Alignment requirements are rare, even for structs.

 OK, so there's one case: pointers in order to make sure the GC works
 properly. =C2=A0But this is absolute alignment. =C2=A0Maybe it's just me=


 that talk of alignment is nearly always in relation to structs, I'd made=


 out to be talking about relative alignment. =C2=A0Maybe the spec just ne=


 clearer....

 Stewart.

Probably. Unions tend to get forgotten.

Apr 16 2009
prev sibling parent reply Michel Fortin <michel.fortin michelf.com> writes:
On 2009-04-13 09:43:53 -0400, Frits van Bommel 
<fvbommel REMwOVExCAPSs.nl> said:

 (How does this combine with the "D ABI" anyway? I know binary 
 compatibility between the different compilers is a bit of a pipe dream 
 at the moment, but the only way that could work would be to standardize 
 any and all shuffling of class fields...)

Interesting observation. But you don't necessarily need to standardize the shuffling algorithm. If the offsets for fields in a class could be resolved at link time (the compiler could dump the offsets in the object file), then the linker could arange the final executable for any layout. The same could be done for virtual functions too, giving us a true non-fragile ABI capable of supporting changes in the order of member fields and functions. -- Michel Fortin michel.fortin michelf.com http://michelf.com/
Apr 14 2009
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Michel Fortin wrote:
 On 2009-04-13 09:43:53 -0400, Frits van Bommel 
 <fvbommel REMwOVExCAPSs.nl> said:
 
 (How does this combine with the "D ABI" anyway? I know binary 
 compatibility between the different compilers is a bit of a pipe dream 
 at the moment, but the only way that could work would be to 
 standardize any and all shuffling of class fields...)

Interesting observation. But you don't necessarily need to standardize the shuffling algorithm. If the offsets for fields in a class could be resolved at link time (the compiler could dump the offsets in the object file), then the linker could arange the final executable for any layout. The same could be done for virtual functions too, giving us a true non-fragile ABI capable of supporting changes in the order of member fields and functions.

Some problems I see with this: * Good luck implementing that for all of OMF (DMD/win), COFF (GDC/win), ELF(anything *nix). * Same for LLVM bitcode, for LDC and any other future compilers based on LLVM. Especially because this is a *typed* IR, and optimizations usually work best if you don't work around types with pointer<-->int conversions. * Implementing this without reducing the quality of generated code; some architectures allow better instructions if you know the offset is below a certain limit, which must then be known at compile-time (except for something like LLVM, where link-time is early enough for this if you're generating IR instead of native code at first). * If you do this, you don't know how big a class body is at compile-time (because padding is unknown). So the compiler doesn't know what size to allocate in the stack frame for 'scope c = new C;" So yeah, in theory this might be possible, but I don't know of any object format that supports all these without it pessimizing the generated code. I just don't think it's worth it at the moment. Though if you feel like extending LLVM to support this... (it's IR object format is probably closest to efficiently supporting something like this due to arbitrarily-complex constant expression support in IR and inter-module optimizations. You might be able to get it to work, as long as the offsets and sizes are known by the time the assembler gets involved) It would certainly allow support for some other cool stuff, like adding fields and (virtual) methods to classes from other object files (aka modules).
Apr 14 2009
prev sibling next sibling parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Mon, Apr 13, 2009 at 2:05 PM, Frits van Bommel
<fvbommel remwovexcapss.nl> wrote:
 Kagamin wrote:
 Stewart Gordon Wrote:

 At the moment, the problem seems to be that the compiler is silently
 ignoring many cases of (a), (b) and (c) alike. =C2=A0Some people argue =



 spec doesn't forbid such use of inapplicable attributes explicitly, and=



 the compiler's treatment of these cannot be called a bug.

 I argue that this isn't right. =C2=A0Nothing I've managed to find in th=



 states or implies that such obviously wrong code is allowed. =C2=A0So, =



 applying common sense, one would conclude that it isn't allowed.

Such mood was always in the spec: "AlignAttribute is ignored when applie=


 to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members? And it won=

 change the alignment of unions if applied to union members (by changing t=

 maximum alignment of the members)?

align is defined in terms of the companion C compiler. align(16) int foo; does not guarantee that foo.offsetof is aligned to 16 by= tes. Since C doesn't have D classes, the align attribute makes little sense here= .
Apr 13 2009
prev sibling next sibling parent "Denis Koroskin" <2korden gmail.com> writes:
On Mon, 13 Apr 2009 16:44:25 +0400, Tomas Lindquist Olsen
<tomas.l.olsen gmail.com> wrote:

 On Mon, Apr 13, 2009 at 2:05 PM, Frits van Bommel
 <fvbommel remwovexcapss.nl> wrote:
 Kagamin wrote:
 Stewart Gordon Wrote:

 At the moment, the problem seems to be that the compiler is silently
 ignoring many cases of (a), (b) and (c) alike.  Some people argue  
 that the
 spec doesn't forbid such use of inapplicable attributes explicitly,  
 and so
 the compiler's treatment of these cannot be called a bug.

 I argue that this isn't right.  Nothing I've managed to find in the  
 spec
 states or implies that such obviously wrong code is allowed.  So, by
 applying common sense, one would conclude that it isn't allowed.

Such mood was always in the spec: "AlignAttribute is ignored when applied to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members? And it won't change the alignment of unions if applied to union members (by changing the maximum alignment of the members)?

align is defined in terms of the companion C compiler. align(16) int foo; does not guarantee that foo.offsetof is aligned to 16 bytes. Since C doesn't have D classes, the align attribute makes little sense here.

You are kind of contradict yourself. Let's assme that align is defined in terms of the companion C compiler. Then, since C doesn't have D classes, the align attribute makes little sense when applied to /D classes/. I don't know how to judge about C built-in types from that.
Apr 13 2009
prev sibling parent Tomas Lindquist Olsen <tomas.l.olsen gmail.com> writes:
On Mon, Apr 13, 2009 at 3:00 PM, Denis Koroskin <2korden gmail.com> wrote:
 On Mon, 13 Apr 2009 16:44:25 +0400, Tomas Lindquist Olsen
 <tomas.l.olsen gmail.com> wrote:

 On Mon, Apr 13, 2009 at 2:05 PM, Frits van Bommel
 <fvbommel remwovexcapss.nl> wrote:
 Kagamin wrote:
 Stewart Gordon Wrote:

 At the moment, the problem seems to be that the compiler is silently
 ignoring many cases of (a), (b) and (c) alike. =C2=A0Some people argu=





 the
 spec doesn't forbid such use of inapplicable attributes explicitly, a=





 so
 the compiler's treatment of these cannot be called a bug.

 I argue that this isn't right. =C2=A0Nothing I've managed to find in =





 spec
 states or implies that such obviously wrong code is allowed. =C2=A0So=





 applying common sense, one would conclude that it isn't allowed.

Such mood was always in the spec: "AlignAttribute is ignored when applied to declarations that are not structs or struct members".

I never saw that before. So it doesn't work for class members? And it won't change the alignment of unions if applied to union members (by changing the maximum alignment of the members)?

align is defined in terms of the companion C compiler. align(16) int foo; does not guarantee that foo.offsetof is aligned to 16 bytes. Since C doesn't have D classes, the align attribute makes little sense here.

You are kind of contradict yourself. Let's assme that align is defined in terms of the companion C compiler. Then, since C doesn't have D classes, the align attribute makes little se=

 when applied to /D classes/.

 I don't know how to judge about C built-in types from that.

Yes now I read it again I can see it doesn't make much sense. What I meant was just to say that align does not work for classes!!! What also snuck in there was that align(N) provides no guarantee that it will actually affect any field offsets. It wasn't supposed to have anything to do with the discussion, so just ignore it if you will...
Apr 13 2009