On Dec 1, 2022, at 1:29 AM, [email protected]<mailto:[email protected]> wrote:

Let's summarize the difference between a primitive type and a primitive class
- a primitive type has a special kind of descriptor, a special kind of opcodes 
(iload vs aload), special kind of arrays (anewarray vs newarray), etc
- a primitive type has a special kind of runtime mirror (int.class, 
double.class, etc)
- a primitive type has a special kind of ==, <, >, etc (float/double semantics 
(IEEE 754) is not compatible with Float/Double semantics)
- a primitive type is always flattened

Some of the differences are historical accidents but for me, the major 
difference between a primitive class and a primitive type is that flattening is 
*guaranteed* for a primitive type and the fact that it has its own descriptor 
and bytecodes is a direct consequence of that decision.

So in term of translation strategy, wanting value/primitive classes to be 
translated in bytecode with the same properties for overloading, etc than 
primitive types should not be a goal.

I could quibble with some of the details (e.g., what does it mean to be 
"guaranteed" to be flattened?—JVMs are free to allocate doubles on heap if they 
really want to, I think), but I share the sentiment. Specifically:

- However we've tried to squeeze the legacy primitives into our story, there 
are always seams. One way or another, they are going to be special. They should 
"fit" with the rest of the story, but it's perfectly fine for certain aspects 
of their treatment to be special-cased. I think it's useful to sometimes break 
away from a "what would 'int' do?" design approach, and instead focus on "how 
should the new feature work, on its own terms?"; then after that's resolved, 
come back and figure out how 'int' fits in.

- There's a tension between making 'Point!' consistent with 'String!' and 
making it consistent with 'int'. Given the identical syntax and the previous 
point about 'int', I'm inclined to prioritize consistency with 'String!'.

- At its core, 'Point!'/'Point' really *doesn't* convey the same 
physical/performance model as 'int'/'Integer'. That's deliberate—a benefit of 
the '!' approach is that it discourages programmers from thinking about 
physical characteristics, and instead focuses them on whether they want 'null' 
in their domain.

- Specifically on overloading, I don't think there's a practical need, at the 
language level, for overloading 'm(Point)' with 'm(Point!)', and it even feels 
like an anti-feature. (E.g., if you're writing that code, you're probably doing 
something wrong.) Overloading of 'int' with 'Integer' makes sense because of 
the physical/performance model, and because of generics limitatations (e.g., 
implementing Predicate<Integer>). Neither of those apply to 'Point!'.

Reply via email to