12 ms·
> why not compile-time error for reading memory that hasn't been written? so... like Rust?
by ratatoskrt 1y ago
> why not compile-time error for reading memory that hasn't been written?
so... like Rust?
- Timwi 1y agoCuriously, 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.
- dontlaugh 1y agoThat’s likely because p/invoke is quite common.
- neonsunset 1y agoNo, 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.
- dontlaugh 1y agoThe main motivation to use unsafe is p/invoke. Without unsafe, zero init is not needed.
- neonsunset 1y ago> The main motivation to use unsafe is p/invoke. This is opposite to the way unsafe (either syntax or known unsafe APIs) is used today.
- dontlaugh 1y agoExplicit use of unsafe is used for things like avoiding allocation, sure. All use of p/invoke is also unsafe though, even if the keyword isn’t used. And it’s much more common to wrap a C library than to write a buffer pool.
- mrkeen 1y agoThis 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.
- electroly 1y agoYou don't need the "default" keyword to run into that. A simple "new Guid()" gives you all-zeroes (try it!). Nice and foot-gunny.
- masfoobar 1y ago> A simple "new Guid()" gives you all-zeroes In C#, to have all zeroes, you would do "Guid.Empty"
- masfoobar 1y ago(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? var myGuid2 = Guid.Empty; // Ah.. all zeroes. It is ESPECIALLY cleaner when doing comparison :- if(myGuid2 == Guid.Empty) { } To set a Guid, you would do :- myGuid2 = Guid.NewGuid(); // This makes sense.
- neonsunset 1y agoOnly 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.
- deleted 1y ago[deleted]
- munificent 1y agoIt 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.)