Good stuff.
On Tue, Nov 2, 2021 at 2:19 PM Brian Goetz <brian.go...@oracle.com> wrote: But, the "traditional" primitives are not nullable, and for good reason; > zero is > a fine default value, > Yes, it would have been impractical to do otherwise, but here's my stock reminder that zero being a "fine" default value has *still nonetheless* caused many thousands of bugs. Again, it had to be done. But I think it's notable that those bugs happen even for the types that have the *absolute most sensible* default values. My concern is that the purest form of value types will be overused and misused for even less clear-cut cases. I would like to think that we can convince these users that they really want the next "bucket" over, which I think comes down to whether the added cost of `null` is worth it. Returning to the tempting user knobs of nullability and tearability, we can > now > put these where they belong: nullability is a property of _reference types_ > -- > Though I've argued loudly here for the notion that nullability is not *conceptually* intrinsic to references (and though I still think we should start saying "the null value" instead of "the null reference"), I nevertheless find this an acceptable compromise, because (a) I think nullable values was just introducing too much practical complexity (b) I hope most use cases really will just use the middle bucket and be fine. Btw, am I right that for the middle bucket, `==` will fail (at compile-time when possible)? The third bucket are the _true primitives_. These are also identity-free > classes, but further give rise to both value and reference types, and the > value > type is the default (we denote the reference type with the familiar > `.ref`.) > Value types are non-nullable, and permit tearing just as existing > primitives do. > The `.ref` type has all the affordances of reference types -- nullability > and > tearing protection. > In fact, if I'm looking at a middle-bucket class, and I'm looking at one of these `.ref` types of "primitive" class, as far as I can tell I should be able to think of these in exactly the same way as exactly the same things. (I'm aware you intend to define `==` differently for the two, but I'll get into my massive concerns about that later.) Basically, that's good. > How we describe the buckets is open to discussion; there are several > possible > approaches. One possible framing is that the middle bucket gives up > identity, > and the third further gives up references (which can be clawed back with > `.ref`), but there are plenty of ways we might express it. > We should address the conceptual-simplicity cost of this "clawing back" sometime. Another open question is whether we double down, or abandon, the > terminology of > boxing. On the one hand, users are familiar with it, and the new > semantics are > the same as the old semantics; on the other, the metaphor of boxing is no > longer > accurate, and users surely have a lot of mental baggage that says "boxes > are > slow." We'd like for users to come to a better understanding of the > difference > between value and reference types. > The key for me is that the new boxing takes over for everything the old boxing did, and more. So, it's better boxing. I see no value in fighting against that. If users are thinking of this by starting from what they know about int/Integer, that's actually *good*. They will just find out it's better, that's all. - Null-adjunction. Some methods, like `Map::get`, return null to indicate > no > mapping was present. But if in `Map<K,V>`, `V` is not nullable, then > there > is no way to express this method. We envision that such methods would > return > `V.ref`, so that strict value-based classes would widened to their > "box" on > return, and null would indicate no mapping present. > Now just spell it `?` :-) (not serious. Also, not not serious) ## Reflection > > Earlier designs all included some non-intuitive behavior around > reflection. > What we'd like to do is align the user-visible types with reflection > literals > with descriptors, following the invariant that > > new X().getClass() == X.class > Seems like part of the goal would be making it fit naturally with the current int/Integer relationship (of course, `42.getClass()` is uncommitted to any precedent). It seems like `Complex.class` (as opposed to `Complex.ref.class`) would never be returned by `Object.getClass()` in any other condition than when you could have just written `Complex.class` anyway. Actually, that makes me start to wonder if `getClass()` should be another method like `notify` that simply doesn't make sense to call on value types. (But we still need the two distinct Class instances per class anyway.) -- Kevin Bourrillion | Java Librarian | Google, Inc. | kev...@google.com