Our story is "Codes like a class, works like an int". A key part of this is that value types support the same lifecycle as objects, and the same ability to hide their internals.

Except, the current story falls down here, because authors must content with the special all-zero default value, because, unlike classes, we cannot guarantee that instances are the result of a constructor. For some classes (e.g., Complex, Point, etc), this forced-on-you default is just fine, but for others (e.g., wrappers for native resources), this is not unlike the regrettable situation with serialization, where class implementations may confront instances that could not have resulted from a constructor.

Classes guard against this through the magic of null; an instance method will never have to contend with a null receiver, because by the time we transfer control to the method, we'd already have gotten an NPE. Values do not have this protection. While there are many things for which we can say "users will learn", I do not think this is one of them; if a class has a constructor, it will be assumed that the receiver in a method invocation will be on an instance that has resulted from construction. I do not think we can expose the programming model as-is; it claims to be like classes, but in this aspect is more like structs.

So, some values (but not all) will want some sort of protection against uninitialized values. One approach here would be to try to emulate null, by, say, injecting checks for the default value prior to dereferences. Another would be to take the route C# did, and allow users to specify a no-arg constructor, which would customize the default value. (Since both are opt-ins, we can educate users about the costs of selecting these tools, and users can get the benefits of flatness and density even if these have additional runtime costs.) The latter route is less rich, but probably workable. Both eliminate the (likely perennial) surprise over uninitialized values for zero-sensitive classes.



Reply via email to