Sorry for delay
On Wed, Jul 13, 2022 at 12:43 PM John Rose <[email protected]> wrote: > The latest iteration of the user model for value classes makes it crystal > clear that one value class C defines two types. > > The second type is named C.val (at present, until that bikeshed is > repainted). This is the “value companion” to C, or maybe its “companion > value type”. > > The term “companion” tries to capture the idea that the class doesn’t come > alone but travels with some friends, its types. But this pulls in a long > and difficult discussion about the exact relation between a class and a > type. And then (inevitably) “what’s a class *really*?” and “what’s a type > *really*?” > > I think we want to make a distinction between a class and a type. A class > is primarily a bunch of source code, later compiled into a classfile. A > type is the primary static attribute of a variable in source code, > determining its range of values and set of valid operations. As later > compiled, the type determines a JVM-level type (usually what we call a > field descriptor). The type probably also determines something of the > eventual format of the variable in a real machine, although that’s a secret > the JVM keeps. > (I know the 3 people regularly participating in these threads are already well-aware, sorry...) My own answer to the question has been Understanding classes and types in Java <https://docs.google.com/document/d/1G5dNQ0kQwA5zefGdP_nvFJByb63QNlz0XiSjltiJM84/edit> (comments welcome). I see a class as a way to "configure" and feed behavior into a type (apart from classes *also* serving as bundles of static members). It's a fairly subservient relationship, which feels right to me. In some of our discussions we have called the other companion type of C, > which is the (nullable) reference type, by the name C.ref, as if it were > something you could write in source code. Perhaps I should be saying > C.__REF to avoid giving that impression. But perhaps not. > > (A generic class can engender many, many types. Is this a whole mob of > companion types? Perhaps not, but it does call for a clear term for this > other relation of classes to types.) > (Sorry for digression: you could also say one class engenders many array types, though. I think it helps to fully distinguish predefined, user-defined, and composed types. Setting aside value classes temporarily: each class directly defines just one type, which is the type of `this` inside the class itself (the "implicit type", or the "this-type"). That's the all-important type whose member signatures are seen in the class and whose supertypes are seen in the class signature. Other types can be composed out of the defined types: array types, type variables, intersection types I guess, and relevant to us here, all *other* parameterized types beyond the implicit type. That is, imho it's most fruitful to understand those parameterized types as deriving from the implicit type/"this-type", with member signatures and supertypes being calculated from that implicit type via substitution, rather than to see them all as popping directly off of the generic class.) > (Note also that the “raw type” of a generic class is named by just the > class name, sans type arguments: Plain List instead of List<String>. And > not List.raw, at least not today.) > > To me it seems useful to treat the two types with a certain amount of > symmetry. There is one class, and two companion types, not a class (which > is also a type), plus its companion (value) type. > > If we do this, it makes some further sense to give them symmetrical names, > C.ref and C.val. We then say that the class name C, used in a context > that requires a type, is “just sugar” for the more exact C.ref (and > certainly not C.val, or you would have used that name). > Are there other uses for C.ref? I can think of just two: > > - > > For type variables (*which are not classes*) T.ref (or some other > bikeshed color) means “recover the reference companion, even if the generic > argument was a value type”. > - > > For extreme stylized clarity in source code, where someone wants to > emphasize that a variable is nullable. (Could this interact with > null-inference schemes? Oh, certainly!) > > I see some sense in your argument, but I still can't think of a reason I'd want to see `ClassName.ref` in source code. It seems like that can't add any information. > - The use T.ref lends weight to making the companions symmetric. You > can go from C meaning C.ref to C.val in List<C.val> and then inside > List you can go back to C.ref. It’s a two-way street. > > There is a limit to treating the two companions symmetrically. Do we > really want to allow inner declarations of the form public companion type > C.ref;, on the grounds that we do so for the companion C.val? No, because > reference types are “hardwired” by present JVM specifications, and > presumably future ones. > > Maybe we will turn, in the end, to a maximally asymmetric design, with no > symmetrical treatment anywhere; no C.ref in particular. But the cost of > that is never being able to refer unambiguously to C as class or as > ref-type, except using informal notations or narrative prose. > > At the moment, though, I like these rules, personally: > > - For a value class name C, C.val names a type. > - For any class or interface name C, C.ref names a type, meaning the > same thing as C. > - For any type variable T (in new generics), T.ref names a type. > - Maybe: For any type variable T (in specialized generics?), T.val > also names a type. > > If I ever see `T.val` (except maybe the case of `T.val[]`??) I will assume some kind of templating must be going on, since we'll all have learned early on that there is no polymorphic interaction with values. Is that your expectation too? > - The ref and val suffixes cannot be applied elsewhere. (So no > C.ref.val.) > > Comments? > -- Kevin Bourrillion | Java Librarian | Google, Inc. | [email protected]
