-
Notifications
You must be signed in to change notification settings - Fork 89
15.6.6.2 (and 15.13, 16.4.11) Type initialisation, as reported by CLI and C# #73
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
Comments
Mads to clarify current implementation in Microsoft and then assign to someone from Xamarin to check the Mono behaviour. |
All comments prior to this one were before we removed section 7. I've updated the title only. |
This is a (slightly, converted from email HTML to MD using the first online convertor I found) better formatted version of the first post above. Section numbers have also been updated to match v5 and one change made to Standard since this was written has been At the April meetings in Geneva I had action items from both TG2 & TG3 (Jim Miller shared my TG3 one) to report back on what the intended story on type initialisation is. The aim was to try to resolve the issue within four weeks after the meeting so any change required could be made to the Standard. We didn't get a resolution in time. I did however investigate the situation. The CLI & C# differ is what they state, and reality is different again - though MS & Mono sometimes differ it is not in substance. We put a note in the forthcoming Annotated C# Standard, and I forgot to report back to TG2 & TG3 once the deadline has passed... So my apologies for forgetting, here it is what I found for the record. Thanks in particular to Jan Kotas for feedback. If we ever produce another edition we can consider what to do with these discrepancies. Below is (a) what the CLI spec says, (b) what the C# spec says, and (c) what is actually implemented: (a) CLI:
(b) C#:
(c) What is actually implemented:
No consensus was achieved and what the CLI or C# should be saying/doing, mainly due to the fact we couldn't do anything about it anymore... |
And now of course we have more flavours of .NET to consider. I suspect we may just want to close this - but if not, I'd want to at least reinterpret the above for clarity... I'm getting very confused by it. It would be good to have some concrete examples where C# and the CLI spec differ (e.g. "C# would permit output of X; CLI would prohibit it"). |
(Marking as "bug" speculatively. It's not entirely clear whether it will be a bug or not.) |
Raised by Nigel in October 2006
"At the April meetings in Geneva I had action items from both TG2 & TG3 (Jim Miller shared my TG3
one) to report back on what the intended story on type initialisation is. The aim was to try to resolve
the issue within four weeks after themeeting so any change required could be made to the Standard.
We didn't get a resolution in time.
I did however investigate the situation. The CLI & C# differ is what they state, and reality is different
again - though MS & Mono sometimes differ it is not in substance. We put a note in the forthcoming
Annotated C# Standard, and I forgot to report back to TG2 & TG3 once the deadline has passed...
So my apologies for forgetting, here it is what I found for the record. Thanks in particular to Jan Kotas for feedback. If we ever produce another edition we can consider what to do with these
discrepancies.
Below is (a) what the CLI spec says, (b) what the C# spec says, and (c) what is actually implemented:
(a) CLI:
The CLI currently states:
before, first access to any static field defined for that type.
triggered by):
or
methods defined by its base type, nor of any interfaces that the type implements
For reference types, a constructor has to be called to create a non-null instance. Thus, for
reference types, the .cctor will be called before instance fields can be accessed and methods
can be called on non-null instances. For value types, an ""all-zero"" instance can be created
without a constructor (but only this value can be created without a constructor). Thus for value
types, the .cctor is only guaranteed to be called for instances of the value type that are not ""allzero"".
[Note: This changes the semantics slightly in the reference class case from the first
edition of this standard, in that the .cctor might not be called before an instance method is
invoked if the 'this' argument is null. The added performance of avoiding class constructors
warrants this change. end note]
Which can be summarised as:
BFI then at or before first static field access
!BFI at first static field access, static method call or .ctor call
never on instance field access or instance method call (for structs)
(b) C#:
C# currently says:
17.11:
The execution of a static constructor is triggered by the first of the following events to occur
within an application domain:
17.4.5.1:
If a static constructor (§17.11) exists in the class, execution of the static field initialisers
occurs immediately prior to executing that static constructor. Otherwise, the static field
initialisers are executed at an implementation-dependent time prior to the first use of a
static field of that class.
18.3.10:
Static constructors for structs follow most of the same rules as for classes. The execution of
a static constructor for a struct is triggered by the first of the following events to occur within
an application domain:
[Note: The creation of default values (§18.3.4) of struct types does not trigger the static
constructor. (An example of this is the initial value of elements in an array.) end note]
Which can be summarised as:
No static constructor but fields inits => BFI
Class and !BFI at first static field access, static method call or .ctor call
Struct and !BFI at first field (static or instance) access, first method (static or instance) call, or
first .ctor call
(c) What is actually implemented:
(i) CLR & Mono
First Mono C# marks all structs as BFI regardless of whether there is a static constructor or
not. VS 2005 C# plays more freely with BFI timing, often for reasons that are not immediately
obvious. However if at is always read as at or before then there are no substantive
differences between the two.
BFI appears to be interpreted as init may trigger before it would for !BFI but it will trigger (it it
hasn't already) at the places !BFI will. I.e. BFI can still trigger even if there is no static field
access at all.
For classes apart from BFI matches CLI/C# spec.
For structs type init is triggered at (or before) first static field access, first static/instance
method call, or first .ctor call.
This is more than the CLI allows as it triggers on instance method access, but less than C#
requires as it doesn't trigger on instance field access. Also the fact the BFI triggers without
static field access also differs from CLI. So all three are different.
(ii) CLR NGEN
If BFI appears to require field access to trigger.
For classes appears to match CLI/C# spec.
For structs appears to match CLI spec.
So I think NGEN is matching the CLI spec.
No consensus was achieved and what the CLI or C# should be saying/doing, mainly due to the fact
we couldn't do anything about it anymore..."
The text was updated successfully, but these errors were encountered: