-
-
Notifications
You must be signed in to change notification settings - Fork 387
Update struct.dd - postblit documentation #2281
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
19bdc68
a272807
3e7965e
7c10ca4
86dee93
0ab9071
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -566,6 +566,271 @@ $(GNAME Postblit): | |
| } | ||
| --- | ||
|
|
||
| $(P Depending on the struct layout, the compiler may generate the following | ||
| internal postblit functions:) | ||
|
|
||
| $(OL | ||
| $(LI `void __postblit()`. The compiler assigns this name to the explicitly | ||
| defined postblit `this(this)` so that it can be treated exactly as | ||
| a normal function. Note that if a struct defines a postblit, it cannot | ||
| define a function named `__postblit` - no matter the signature - | ||
| as this would result in a compilation error due to the name conflict.) | ||
| $(LI `void __fieldPostblit()`. If a struct `X` has at least one `struct` | ||
| member that in turn defines (explicitly or implicitly) a postblit, then a field | ||
| postblit is generated for `X` that calls all the underlying postblits | ||
| of the struct fields in declaration order.) | ||
| $(LI `void __aggrPostblit()`. If a struct has an explicitly defined postblit | ||
| and at least 1 struct member that has a postblit (explicit or implicit) | ||
| an aggregated postblit is generated which calls `__fieldPostblit` first | ||
| and then `__postblit`.) | ||
| $(LI `void __xpostblit()`. The field and aggregated postblits, although | ||
| generated for a struct, are not actual struct members. In order to be able | ||
| to call them, the compiler internally creates an alias, called `__xpostblit` | ||
| which is a member of the struct and which points to the generated postblit that | ||
| is the most inclusive.) | ||
| ) | ||
|
|
||
| $(SPEC_RUNNABLE_EXAMPLE_COMPILE | ||
| --- | ||
| // struct with alias __xpostblit = __postblit | ||
| struct X | ||
| { | ||
| this(this) {} | ||
| } | ||
|
|
||
| // struct with alias __xpostblit = __fieldPostblit | ||
| // which contains a call to X.__xpostblit | ||
| struct Y | ||
| { | ||
| X a; | ||
| } | ||
|
|
||
| // struct with alias __xpostblit = __aggrPostblit which contains | ||
| // a call to Y.__xpostblit and a call to Z.__postblit | ||
| struct Z | ||
| { | ||
| Y a; | ||
| this(this) {} | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| // X has __postblit and __xpostblit (pointing to __postblit) | ||
| static assert(__traits(hasMember, X, "__postblit")); | ||
| static assert(__traits(hasMember, X, "__xpostblit")); | ||
|
|
||
| // Y does not have __postblit, but has __xpostblit (pointing to __fieldPostblit) | ||
| static assert(!__traits(hasMember, Y, "__postblit")); | ||
| static assert(__traits(hasMember, Y, "__xpostblit")); | ||
| // __fieldPostblit is not a member of the struct | ||
| static assert(!__traits(hasMember, Y, "__fieldPostblit")); | ||
|
|
||
| // Z has __postblit and __xpostblit (pointing to __aggrPostblit) | ||
| static assert(__traits(hasMember, Z, "__postblit")); | ||
| static assert(__traits(hasMember, Z, "__xpostblit")); | ||
| // __aggrPostblit is not a member of the struct | ||
| static assert(!__traits(hasMember, Z, "__aggrPostblit")); | ||
| } | ||
| --- | ||
| ) | ||
|
|
||
| $(P Neither of the above postblits is defined for structs that don't | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should specify somewhere (perhaps here) what happens if someone does NOT define |
||
| define `this(this)` and don't have fields that transitively define it. | ||
| If a struct does not define a postblit (implicit or explicit) but | ||
| defines functions that use the same name/signature as the internally | ||
| generated postblits, the compiler is able to identify that the functions | ||
| are not actual postblits and does not insert calls to them when the | ||
| struct is copied. Example:) | ||
|
|
||
| $(SPEC_RUNNABLE_EXAMPLE_COMPILE | ||
| --- | ||
| struct X | ||
| {} | ||
|
|
||
| int a; | ||
|
|
||
| struct Y | ||
| { | ||
| int a; | ||
| X b; | ||
| void __fieldPostPostblit() | ||
| { | ||
| a = 42; | ||
| } | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| static assert(!__traits(hasMember, X, "__postblit")); | ||
| static assert(!__traits(hasMember, X, "__xpostblit")); | ||
|
|
||
| static assert(!__traits(hasMember, Y, "__postblit")); | ||
| static assert(!__traits(hasMember, Y, "__xpostblit")); | ||
|
|
||
| Y y; | ||
| auto y2 = y; | ||
| assert(a == 0); // __fieldPostBlit does not get called | ||
| } | ||
| --- | ||
| ) | ||
|
|
||
| $(P Postblits cannot be overloaded. If two or more postblits are defined, | ||
| even if the signatures differ, the compiler assigns the | ||
| `__postblit` name to both and later issues a conflicting function | ||
| name error:) | ||
|
|
||
| --- | ||
| struct X | ||
| { | ||
| this(this) {} | ||
| this(this) const {} // error: function X.__postblit conflicts with function X.__postblit | ||
| } | ||
| --- | ||
|
|
||
| $(P The following describes the behavior of the | ||
| qualified postblit definitions:) | ||
|
|
||
| $(OL | ||
| $(LI `const`. When a postblit is qualified with `const` as in | ||
| $(D this(this) const;) or $(D const this(this);) then the postblit | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed the "is ill-formed" part here because the code is accepted. Please don't forget - we're documenting behavior here, not what should happen. If we deprecate this with the next version, then yes please do mention it's ill-formed but no diagnostic is issues by front-end versions prior to 2.xxx.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We will deprecate this with the next version, but @wilzbach argued that information that gets outdated should not be in the spec. I thought that saying it's ill-formed but not mentioning the deprecation is the best compromise since you can actually call the function but it's not doing what it is supposed to.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's helpful to give that information so people who see invalid code getting compiled don't get confused. |
||
| is succesfully called on mutable (unqualified), `const`, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I removed the backquotes around mutable because mutable is not a keyword. |
||
| and `immutable` objects, but the postblit cannot modify the object | ||
| because it regards it as `const`; hence `const` postblits are of | ||
| limited usefulness. Example:) | ||
|
|
||
| $(SPEC_RUNNABLE_EXAMPLE_COMPILE | ||
| --- | ||
| struct S | ||
| { | ||
| int n; | ||
| this(this) const | ||
| { | ||
| import std.stdio : writeln; | ||
| writeln("postblit called"); | ||
| //++n; // error: cannot modify this.n in `const` function | ||
| } | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| S s1; | ||
| auto s2 = s1; | ||
| const S s3; | ||
| auto s4 = s3; | ||
| immutable S s5; | ||
| auto s6 = s5; | ||
| } | ||
| --- | ||
| ) | ||
| $(LI `immutable`. When a postblit is qualified with `immutable` | ||
| as in $(D this(this) immutable) or $(D immutable this(this)) | ||
| the code is ill-formed. The `immutable` postblit passes the | ||
| compilation phase but cannot be invoked. Example:) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Version when this will be diagnosed? I think we can leave this text as is and add a mention once we merge the appropriate PR. |
||
|
|
||
| --- | ||
| struct Y | ||
| { | ||
| // not invoked anywhere, no error is issued | ||
| this(this) immutable | ||
| { } | ||
| } | ||
|
|
||
| struct S | ||
| { | ||
| this(this) immutable | ||
| { } | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| S s1; | ||
| auto s2 = s1; // error: immutable method `__postblit` is not callable using a mutable object | ||
| const S s3; | ||
| auto s4 = s3; // error: immutable method `__postblit` is not callable using a mutable object | ||
| immutable S s5; | ||
| auto s6 = s5; // error: immutable method `__postblit` is not callable using a mutable object | ||
| } | ||
| --- | ||
|
|
||
| $(LI `shared`. When a postblit is qualified with `shared` as in | ||
| $(D this(this) shared) or $(D shared this(this)) solely `shared` | ||
| objects may invoke the postblit; attempts of postbliting unshared | ||
| objects will result in compile time errors:) | ||
|
|
||
| --- | ||
| struct S | ||
| { | ||
| this(this) shared | ||
| { } | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| S s1; | ||
| auto s2 = s1; // error: shared method `__postblit` is not callable using a non-shared object | ||
| const S s3; | ||
| auto s4 = s3; // error: shared method `__postblit` is not callable using a non-shared object | ||
| immutable S s5; | ||
| auto s6 = s5; // error: shared method `__postblit` is not callable using a non-shared object | ||
|
|
||
| // calling the shared postblit on a shared object is accepted | ||
| shared S s7; | ||
| auto s8 = s7; | ||
| } | ||
| --- | ||
| ) | ||
|
|
||
| $(P An unqualified postblit will get called even if the | ||
| struct is instantiated as `immutable` or `const`, but | ||
| the compiler issues an error if the struct is instantiated | ||
| as shared:) | ||
|
|
||
| $(SPEC_RUNNABLE_EXAMPLE_COMPILE | ||
| --- | ||
| struct S | ||
| { | ||
| int n; | ||
| this(this) { ++n; } | ||
| } | ||
|
|
||
| void main() | ||
| { | ||
| immutable S a; // shared S a; => error : non-shared method is not callable using a shared object | ||
| auto a2 = a; | ||
| import std.stdio: writeln; | ||
| writeln(a2.n); // prints 1 | ||
| } | ||
| --- | ||
| ) | ||
|
|
||
| $(P From a postblit perspective, qualifiying the struct definition | ||
| yields the same result as explicitly qualifying the postblit.) | ||
|
|
||
| $(P The following table lists all the possibilities of grouping | ||
| qualifiers for a postblit associated with the type of object that | ||
| needs to be used in order to succesfully invoke the postblit:) | ||
|
|
||
| $(TABLE_10 $(ARGS Qualifier Groups), | ||
| $(VERTROW object type to be invoked on, $(D const), $(D immutable), $(D shared)), | ||
| $(TROW any object type, $(YES), $(NO), $(NO) ) | ||
| $(TROW uncallable, $(NO), $(YES), $(NO) ) | ||
| $(TROW shared object, $(NO), $(NO), $(YES)) | ||
| $(TROW uncallable, $(YES), $(YES), $(NO) ) | ||
| $(TROW shared object, $(YES), $(NO), $(YES)) | ||
| $(TROW uncallable, $(NO), $(YES), $(YES)) | ||
| $(TROW uncallable, $(YES), $(YES), $(YES)) | ||
| ) | ||
|
|
||
| $(P Note that when `const` and `immutable` are used to explicitly | ||
| qualify a postblit as in `this(this) const immutable;` or | ||
| `const immutable this(this);` - the order in which the qualifiers | ||
| are declared does not matter - the compiler generates a `conflicting | ||
| attribute error`, however declaring the struct as `const`/`immutable` | ||
| and the postblit as `immutable`/`const` achieves the effect of applying | ||
| both qualifiers to the postblit. In both cases the postblit is | ||
| qualified with the more restrictive qualifier, which is `immutable`. | ||
| ) | ||
|
|
||
| $(P Unions may not have fields that have postblits.) | ||
|
|
||
| $(H2 $(LEGACY_LNAME2 StructDestructor, struct-destructor, Struct Destructors)) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please specify entire signatures (as I did in the commit I added) and make sure those I added are correct.