Open dsyme opened 5 years ago
A possible way to overcome this could be adding a special attribute effectively disabling the check, as it's been discussed. It would allow doing some nasty stuff but probably is a good compromise for cases it's needed in unless there's no other way that isn't too complex to implement.
I'm not sure how to fix this through automatic analysis. Detecting the lack of recursive access is annoyingly hard, and has to be done at "just the right stage" in the process of checking classes and converting them to their TAST form.
As @auduchinok says, the alternative would be to have an attribute disabling initialization safety checks for a module, or type, or the like. This would make sense for a number of micro-perf reasons for code the programmer is happy to declare safe, akin to DefaultValue
and so on. Given it would be opt-in this would be ok.
The F# compiler emits "init" field checks to prevent access of bindings before initialization is complete. This is for soundness.
However, this impacts performance for a normal implementation of some immutable types where these safety checks are not needed.
Thanks to @auduchinok for reporting this.
Repro steps
Consider this code:
The compiled form of this code has an inserted static
init
field which is checked on each access toEmpty
, see below. The same applies for non-generic and non-struct types.The F# compiler does this for good reasons - without it it is possible to read uninitialized bindings too easily and without any warning, e.g. consider the following small variation:
Ideally, the F# compiler would automatically detect the most important cases where safety checks are not required.
Here is the ILDASM for the original:
and