RefObject and ValObject
Maurizio Cimadamore
maurizio.cimadamore at oracle.com
Mon Apr 15 14:30:24 UTC 2019
Mu suggestion here is to leave subtyping on the side, at least for now
and use some other way to describe what's going on.
Let's model the value vs. reference constraint explicitly - e.g. with
'val' and 'ref' type kinds (and let's not open the can worm as to what
the syntax should be, whether it should be a type anno, etc.)
So:
val Object ---> accepts all values
ref Object ---> accepts all references
any Object ---> accepts all references
Now that everything is explicit, for types we have two possible moves:
1) reinterpret `Object` as `ref Object`
This will keep semantics as is - that is, upon recompilation, if source
code doesn't change, a program that expected references cannot start
receiving value parameters. If code wants to work on both references and
values, it will have to opt in (by using `any`).
2) reinterpret `Object` as `any Object`
That is, the semantics of `Object` is being redefined here - code which
assumed to work with references might need to opt-in to additional
constraints (e.g. add `ref`) in order to make sure it still work as
intended.
I think we are leaning towards (2) - that is, we want meaning of Object
to be upgraded, and we want users that are not happy with that to opt
out in some form.
Ok, now let's think about expressions; given an expression E, I have to
figure out (i) its type and its (ii) kind, since the type system I'm
describing here takes both factors into account.
Here I'm expecting rules of the kind:
a) if E is an identifier pointing to a variable decl, then type and kind
are derived from the declaration
b) if E is a method call, where declared method is M, type and kind are
derived from M's return type declaration
...
z) if E is a new expression, of the kind `new T()`, the type is T and
the kind can be either `ref` or `val` depending on whether T is a
reference class or not. If T can be both, then kind `any` is inferred.
So, we can use (z) e.g. to say that `new String()` has kind `ref`. But,
if we want Object to be the top type for both values and references, I
believe one consequence is that `new Object` is interpreted as `any`
which means you cannot pass it to `ref Object`.
I don't see another way out of this conundrum - other than adding a
special rule (z2) which says that `new Object()` is treated specially
and always has kind `ref`. But doing so will run afoul in almost every
possible way - as soon as you manipulate the result of the `new` in any
way (cast, assignment to variable of type `Object`, ...) you go back to
`any` and you are back to a place that is incompatible with `ref Object`.
Your idea of treating Object as abstract is, I believe, a sound one
(which doesn't need any extra rule) - but we might have to figure out
some story for anonymous inner classes of the kind `new Object() { ... }`.
Maurizio
On 15/04/2019 14:26, Brian Goetz wrote:
>
>
>> But the other concerns remain, e.g. as to the fact that the boundary
>> between reinterpreted types (Object as RefObject) and
>> non-reinterpreted types (Object as top type) seems very fuzzy.
>
> Right, which is why we’re still searching for an answer :)
>
> We really, really want to be able to represent ref/val-ness in the
> type system. Why? Ignoring pedagogical concerns (which are
> significant):
>
> - If certain operations (e.g., locking) are partial, we want to be
> able to provide a way to ask if the operation could succeed. Such as:
>
> if (x instanceof RefObejct) { … lock on x … }
>
> Saying “lock, and hope it doesn’t throw” is not a very good answer.
> We already have a tool for querying the dynamic type of an object —
> instanceof.
>
> - Saying that a method should only accept reference objects should be
> something expressible in the method signature, as in
>
> m(RefObject o) { … }
>
> Types are how we do that.
>
> - Similarly, we might want to express the above constraint
> generically; again, types are the way we do that:
>
> class Foo<T extends RefObject> { }
>
>
> And, Q-world already taught us that we wanted to retain Object as the
> top type. This mean, necessarily, that Object gets a little weirder;
> it takes on some partly-class, partly-interface behavior.
>
> Here’s an idea: What if we migrated `Object` to be an abstract class?
> The casualty would be the code that says `new Object()`. While
> there’s certainly a lot of it out there, perhaps this is something
> amenable to migration:
>
> - At the source level, for N versions, `new Object()` gets a warning
> that says “I’ll pretend you said `Object.newLockInstance()` or something.
> - At the bytemode level, for M versions, we do something similar,
> likely for M > N.
>
> We can start this now, before Valhalla even previews.
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/valhalla-spec-experts/attachments/20190415/a5e093b1/attachment.html>
More information about the valhalla-spec-experts
mailing list