Curiously, C# does both. It uses compile-time checks to stop you from accessing an uninitialized local and from exiting a struct constructor without initializing all fields; and yet, the CLR (the VM C# compiles to) zero-initializes everything anyway.
It has to because the analysis to detect that fields are initialized in the constructor body is unsound. Since you have access to `this` inside the constructor, you can call other instance methods which may access fields before they have been initialized.
Java has the same problem.
(Dart, which I work on, does not. In Dart, you really truly can't observe an instance field before it has been initialized.)
This is a pain. I recently switched from Java (and its whole Optional/null mess) to C#. I was initially impressed by its nullable checks, but then I discovered 'default'. Now I gotta check that Guids aren't 0000...? It makes me miss the Java situation.
(continued from my comment above)
Apologies, I am missing some text on here. No sure what happened. I might have deleted before I submitted. I cannot edit this comment, but I need to clarify and correct it...
"new Guid()" is equiverlant "Guid.Empty"
Personally, I would prefer writing "Guid.Empty" as it is cleaner. It also helps ensure you understand reading other developers code... their intensions.
Afterall, a lesser experienced developer may not know (or simply forgot) that "new Guid()" does not create a new, unique value. So writing "new Guid()" looks more misleading.
var myGuid1 = new Guid(); // all zeroes, or a value?
Only if you go out of your way to author a method with (Guid someGuid = default) argument. I've never seen it happen with Guids, if someone gives you default(Guid) - they did it on purpose, it's no different to explicitly setting `0` to an integer-typed UserID property.
If supplying Guid is optional, you just make it Guid?.
To be fair, I don't think offering default(T) by default (ha) is the best choice for structs. In F#, you have to explicitly do `Unchecked.defaultOf` and otherwise it will just not let you have your way - it is watertight. I much prefer this approach even if it can be less convenient at times.
No, that's just the memory model of CLI and the choice made by C#. By default, it emits localsinit flag for methods which indicates that all local variables must be zero-initialized first. On top of that, you can't really access unitialized memory in C# and F# anyway unless you use unsafe. It's a memory safety choice indeed but it has nothing to do with P/Invoke.
so... like Rust?