Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> why not compile-time error for reading memory that hasn't been written?

so... like Rust?



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.


You don't need the "default" keyword to run into that. A simple "new Guid()" gives you all-zeroes (try it!). Nice and foot-gunny.


> A simple "new Guid()" gives you all-zeroes

In C#, to have all zeroes, you would do "Guid.Empty"


(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.


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.


That’s likely because p/invoke is quite common.


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.


The main motivation to use unsafe is p/invoke.

Without unsafe, zero init is not needed.


> 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.


Explicit 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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: