Re: RefObject and ValObject

2019-04-18 Thread John Rose
On Apr 15, 2019, at 1:37 PM, fo...@univ-mlv.fr wrote:
> 
> It's not bikeshedding, hence the "if you prefer ...",
> it's trying to explain that it's a typing issue and not a runtime class issue.

Sure.  The "if you prefer" is a subtle hint that bikeshedding is
not intended.  To avoid having your audience think that
bikeshedding has begun, a *non-subtle* hint is even more
helpful, which is why I like to use intentionally ugly
pseudo-syntax (like __NWC_BLOB__, in another thread)
during such discussions.


> - Mail original -
>> De: "John Rose" 
>> À: "Remi Forax" , "Maurizio Cimadamore" 
>> 
>> Cc: "Brian Goetz" , "valhalla-spec-experts" 
>> 
>> Envoyé: Lundi 15 Avril 2019 20:13:50
>> Objet: Re: RefObject and ValObject
> 
>> Avoid the Bikeshed!  Make sure that temporary or provisional
>> syntaxes look __Different from permanent ones.
>> 



Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore



On 15/04/2019 21:54, fo...@univ-mlv.fr wrote:

m(List list ) {  ... }
  ...
  m(List.of(new Foo(), new Bar()));


Slightly incorrect sir :-)

This is effectively equivalent to the example I wrote earlier

List list = List.of(...)

The expected type will force the equality constraint and will drive 
inference home.


Otherwise it would not even work today in cases when you pass e.g. 
Integer and String to List.of, as their common supertype is something 
sharper than Object. This stuff used indeed to fail pre-Java 8, but I 
think we cured most of the issues. The remaining ones are when inference 
eagerly resolves variables w/o looking at the target, because a target 
is not there, as for 'var', or because the expression is in a receiver 
position, as in:


List list2 = List.of(new Foo(), new Bar()).subList(0, 42);

Now, this will fail, but I believe we're in the corner^2 territory?

Maurizio




Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
Most of what i wrote in the L10/L20 memo is accurate :)

> On Apr 15, 2019, at 5:32 PM, fo...@univ-mlv.fr wrote:
> 
> 
> 
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 23:23:57
> Objet: Re: RefObject and ValObject
> V <: V? by value set inclusion; V? is the type obtained by adjoining `null` 
> to the value set of V.  
> 
> Looking for.a better name for this.  :”Nullable value types” is a terrible 
> name, so I don’t want to say that.  (Too confusing with null-default value 
> types.). They could properly be define as “null-adjoined value types”, but 
> that’s not helpful if you don’t know what an adjunction is.  Similarly for 
> “nullable projection”.  
> 
> But the basic idea is that V? is the denotation of the union type of V | 
> Null.  
> 
> 
> Ok, i think i got slightly confused about the difference between RefObject 
> and ValueRef?
> 
> Rémi
> 
>  
> 



Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 23:23:57
> Objet: Re: RefObject and ValObject

>> V <: V? by value set inclusion; V? is the type obtained by adjoining `null` 
>> to
>> the value set of V.

> Looking for.a better name for this. :”Nullable value types” is a terrible 
> name,
> so I don’t want to say that. (Too confusing with null-default value types.).
> They could properly be define as “null-adjoined value types”, but that’s not
> helpful if you don’t know what an adjunction is. Similarly for “nullable
> projection”.

> But the basic idea is that V? is the denotation of the union type of V | Null.

Ok, i think i got slightly confused about the difference between RefObject and 
ValueRef? 

Rémi 


Re: RefObject and ValObject

2019-04-15 Thread John Rose
The word "reference" is available and fits the bill.
"nullable reference type"

> On Apr 15, 2019, at 2:23 PM, Brian Goetz  wrote:
> 
>> V <: V? by value set inclusion; V? is the type obtained by adjoining `null` 
>> to the value set of V.  
> 
> Looking for.a better name for this.  :”Nullable value types” is a terrible 
> name, so I don’t want to say that.  (Too confusing with null-default value 
> types.). They could properly be define as “null-adjoined value types”, but 
> that’s not helpful if you don’t know what an adjunction is.  Similarly for 
> “nullable projection”.  
> 
> But the basic idea is that V? is the denotation of the union type of V | 
> Null.  
> 



Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> V <: V? by value set inclusion; V? is the type obtained by adjoining `null` 
> to the value set of V.  

Looking for.a better name for this.  :”Nullable value types” is a terrible 
name, so I don’t want to say that.  (Too confusing with null-default value 
types.). They could properly be define as “null-adjoined value types”, but 
that’s not helpful if you don’t know what an adjunction is.  Similarly for 
“nullable projection”.  

But the basic idea is that V? is the denotation of the union type of V | Null.  



Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
In the document on “Towards a plan for L10 / L20” I tried to answer these, but 
I got it slightly wrong.  I said:

   V <: V? <: ValObject <: Object

But really that should be 

   V <: V? <: ValObject? <: Object
   V <: ValObject <: Object

V <: V? by value set inclusion; V? is the type obtained by adjoining `null` to 
the value set of V.  

I am leaning towards saying that `RefObject?` and `Object?` are not sensible 
things to write, because they are equal to `RefObject` and `Object`.  (That’s 
separately from `T?`, which always makes sense, but sometimes just means “T”.). 

No flavor of Point is a subtype of any flavor of RefObject; ValObject and 
RefObject are disjoint.  




> On Apr 15, 2019, at 5:10 PM, fo...@univ-mlv.fr wrote:
> 
> 
> 
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Maurizio Cimadamore" , 
> "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 22:46:08
> Objet: Re: RefObject and ValObject
> yes !
> all generics will suddenly accept value types.
> 
> 
> Yes, this is by design.  If you can’t have an ArrayList of Point, that would 
> be terrible.  Of course, until we have specialization (later in the story), 
> these will be erased, and restricted to the nullable projection.  
> 
> Does it means that Point? is a subtype of RefObject ?
> 
> Note: the second question mark in this sentence is because it's a question.
> 
> Rémi
> 



Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Maurizio Cimadamore" ,
> "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 22:46:08
> Objet: Re: RefObject and ValObject

>> yes !
>> all generics will suddenly accept value types.

> Yes, this is by design. If you can’t have an ArrayList of Point, that would be
> terrible. Of course, until we have specialization (later in the story), these
> will be erased, and restricted to the nullable projection.

Does it means that Point? is a subtype of RefObject ? 

Note: the second question mark in this sentence is because it's a question. 

Rémi 


Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Maurizio Cimadamore" 
> À: "Brian Goetz" , "Remi Forax" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 22:53:49
> Objet: Re: RefObject and ValObject

> I think we should be ok inference-wise, except of course for edge cases (like
> vars) which exposes the guts of the inference engine.

> In normal cases like:

> List list = List.of(new Foo(), new Bar())

> the equality constraint on the LHS should force a solution which overrides the
> new 'RefObject' bound that comes in from the RHS.

> (that is, you have T = Object, then T :> Foo and T :> Bar, so T = Object 
> 'wins',
> even if less precise)

> Maurizio
yes, i think you're right, 

Rémi 

> On 15/04/2019 21:39, Brian Goetz wrote:
>>> 1) any codes that has inference
>>> var list = List.of(new Foo(), new Bar());
>>> will be inferred as List instead of List, so calling a 
>>> method
>>> that takes a List will not compile anymore.

>> Not to dismiss the “what about inference” issue, but any code that combines
>> `var` with `List,of()` should not be surprised at the result of inference ….

>> But, “what about inference” noted.

>>> 2) any code that consider Object as special class may stop working, dynamic
>>> proxies that have a special case for Object, any code that reflect 
>>> recursively
>>> on the hierarchy to find all the methods, any code that remove getClass() 
>>> from
>>> the getter list, etc.

>> Absorbing value types is going to require some changes on the part of most
>> frameworks to get best results. This one seems in that category?

>> Again, not to dismiss, keep them coming, but so far this isn’t scaring me 
>> away
>> from having the object model that makes most sense.


Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore
I think we should be ok inference-wise, except of course for edge cases 
(like vars) which exposes the guts of the inference engine.


In normal cases like:

List list = List.of(new Foo(), new Bar())

the equality constraint on the LHS should force a solution which 
overrides the new 'RefObject' bound that comes in from the RHS.


(that is, you have T = Object, then T :> Foo and T :> Bar, so T = Object 
'wins', even if less precise)


Maurizio


On 15/04/2019 21:39, Brian Goetz wrote:



1) any codes that has inference
   var list = List.of(new Foo(), new Bar());
    will be inferred as List instead of List, so 
calling a method that takes a List will not compile anymore.


Not to dismiss the “what about inference” issue, but any code that 
combines `var` with `List,of()` should not be surprised at the result 
of inference ….


But, “what about inference” noted.

2) any code that consider Object as special class may stop working, 
dynamic proxies that have a special case for Object, any code that 
reflect recursively on the hierarchy to find all the methods, any 
code that remove getClass() from the getter list, etc.


Absorbing value types is going to require some changes on the part of 
most frameworks to get best results.  This one seems in that category?


Again, not to dismiss, keep them coming, but so far this isn’t scaring 
me away from having the object model that makes most sense.





Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Maurizio Cimadamore" ,
> "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 22:39:43
> Objet: Re: RefObject and ValObject

>> 1) any codes that has inference
>> var list = List.of(new Foo(), new Bar());
>> will be inferred as List instead of List, so calling a 
>> method
>> that takes a List will not compile anymore.

> Not to dismiss the “what about inference” issue, but any code that combines
> `var` with `List,of()` should not be surprised at the result of inference ….

> But, “what about inference” noted.

you don't need var, var represent the inference value of an expression, instead 
of having two lines, you can always write 
m(List list ) { ... } 
... 
m(List.of(new Foo(), new Bar())); 

>> 2) any code that consider Object as special class may stop working, dynamic
>> proxies that have a special case for Object, any code that reflect 
>> recursively
>> on the hierarchy to find all the methods, any code that remove getClass() 
>> from
>> the getter list, etc.

> Absorbing value types is going to require some changes on the part of most
> frameworks to get best results. This one seems in that category?

> Again, not to dismiss, keep them coming, but so far this isn’t scaring me away
> from having the object model that makes most sense.

but this compatibility issues have nothing to do with value types pre se, it's 
because of the introduction of RefObject, and currently all other compatibility 
issues can be solved at use site (i believe), here you are adding compatibility 
issue that can only be solved at declaration site, that's a big change because 
now as a user you have to wait until all your dependencies have been updated 
before using value type. 

Rémi 


Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Maurizio Cimadamore" 
> À: "Brian Goetz" , "Remi Forax" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 22:23:25
> Objet: Re: RefObject and ValObject

> Maybe (Remi correct me if I'm wrong), the problem Remi was referring to is 
> that
> we also have existing generic declarations like  which, in
> the new world, will mean either VALUE or REFERENCE. I think this is a
> consequence of the choice (1) I described in my email - e.g. reinterpret 
> Object
> in type position as TOP_TYPE.

> Maurizio
yes ! 
all generics will suddenly accept value types. 

Rémi 

> On 15/04/2019 19:00, Brian Goetz wrote:

>>> It's not a minor change, and all code that uses a type parameter that have
>>> Object as bound will become ambiguous.

>> I don’t think so. You can’t say

>> new T()

>> when T is bounded at Object (or anything, for that matter.).

>> What ambiguity are you afraid of here?


Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> 
> 1) any codes that has inference
>var list = List.of(new Foo(), new Bar());
> will be inferred as List instead of List, so calling a 
> method that takes a List will not compile anymore.

Not to dismiss the “what about inference” issue, but any code that combines 
`var` with `List,of()` should not be surprised at the result of inference ….

But, “what about inference” noted.

> 2) any code that consider Object as special class may stop working, dynamic 
> proxies that have a special case for Object, any code that reflect 
> recursively on the hierarchy to find all the methods, any code that remove 
> getClass() from the getter list, etc.

Absorbing value types is going to require some changes on the part of most 
frameworks to get best results.  This one seems in that category?  

Again, not to dismiss, keep them coming, but so far this isn’t scaring me away 
from having the object model that makes most sense.




Re: RefObject and ValObject

2019-04-15 Thread forax
It's not bikeshedding, hence the "if you prefer ...",
it's trying to explain that it's a typing issue and not a runtime class issue.

Rémi

- Mail original -
> De: "John Rose" 
> À: "Remi Forax" , "Maurizio Cimadamore" 
> 
> Cc: "Brian Goetz" , "valhalla-spec-experts" 
> 
> Envoyé: Lundi 15 Avril 2019 20:13:50
> Objet: Re: RefObject and ValObject

> Avoid the Bikeshed!  Make sure that temporary or provisional
> syntaxes look __Different from permanent ones.
> 
> On Apr 15, 2019, at 8:03 AM, Remi Forax  wrote:
>> 
>> val, ref and any only applies to Object.
>> 
>> if you prefer in term of notation, let's rename ref Object to Object?, val
>> Object to Object! and any Object to Object*,
>> 
>> you can apply ? on any value type, Object included,
> > you can apply ! and * only on Object.


Re: RefObject and ValObject

2019-04-15 Thread forax
> De: "Brian Goetz" 
> À: "Remi Forax" 
> Cc: "Maurizio Cimadamore" ,
> "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 20:00:52
> Objet: Re: RefObject and ValObject

>> It's not a minor change, and all code that uses a type parameter that have
>> Object as bound will become ambiguous.

> I don’t think so. You can’t say

> new T()

> when T is bounded at Object (or anything, for that matter.).

> What ambiguity are you afraid of here?

1) any codes that has inference 
var list = List.of(new Foo(), new Bar()); 
will be inferred as List instead of List, so calling a 
method that takes a List will not compile anymore. 

2) any code that consider Object as special class may stop working, dynamic 
proxies that have a special case for Object, any code that reflect recursively 
on the hierarchy to find all the methods, any code that remove getClass() from 
the getter list, etc. 

Rémi 


Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
That’s right, as we think that will be the best default.  Obviously in some 
cases users will want to re-bound to .

(For existing code; this comes with compatibility concerns, which we can handle 
in various ways.  The standard trick to change a bound without changing erasure 
is to bound at Object this works when X is an interface but currently would 
be unhappy if X is a class.  But this could be adjusted.)

> On Apr 15, 2019, at 4:23 PM, Maurizio Cimadamore 
>  wrote:
> 
> Maybe (Remi correct me if I'm wrong), the problem Remi was referring to is 
> that we also have existing generic declarations like  
> which, in the new world, will mean either VALUE or REFERENCE. I think this is 
> a consequence of the choice (1) I described in my email - e.g. reinterpret 
> Object in type position as TOP_TYPE.
> 
> Maurizio
> 
> On 15/04/2019 19:00, Brian Goetz wrote:
>>> 
>>> It's not a minor change, and all code that uses a type parameter that have 
>>> Object as bound will become ambiguous.
>> 
>> I don’t think so.  You can’t say
>> 
>> new T()
>> 
>> when T is bounded at Object (or anything, for that matter.). 
>> 
>> What ambiguity are you afraid of here?
>> 
>> 



Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore
Maybe (Remi correct me if I'm wrong), the problem Remi was referring to 
is that we also have existing generic declarations like Object> which, in the new world, will mean either VALUE or REFERENCE. I 
think this is a consequence of the choice (1) I described in my email - 
e.g. reinterpret Object in type position as TOP_TYPE.


Maurizio

On 15/04/2019 19:00, Brian Goetz wrote:


It's not a minor change, and all code that uses a type parameter that 
have Object as bound will become ambiguous.


I don’t think so.  You can’t say

    new T()

when T is bounded at Object (or anything, for that matter.).

What ambiguity are you afraid of here?




Re: RefObject and ValObject

2019-04-15 Thread John Rose
I think this hangs together very well.

For legacy bytecode (only), the JVM has to be willing to do
these one-time fudges:

- rewrite new java/lang/Object to new java/lang/RefObject
- rewrite invokespecial java/lang/Object.()V to
   invokespecial java/lang/RefObject.()V

The verifier can observe these rewrites, but it may also
take this additional step, for legacy code only:

- widen the type of new java/lang/RefObject to plain Object

(…which would prevent the verifier from passing the
new RefObject to a method that actually takes RefObject.
Not sure that step is useful; it's a "one hand clapping" type
of move, which in practice won't be observable.)

— John

> On Apr 15, 2019, at 8:23 AM, Brian Goetz  wrote:
> 
>> 
>> 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() { ... }`.
> 
> After thinking about it for all of five minutes, I think this may have broken 
> the logjam (or, at least the current logjam.). We’ve been asking ourselves 
> whether RO/VO are classes or interfaces, when we didn’t really consider 
> abstract classes.  Which we didn’t consider because we had assumed that the 
> concrete-ness of Object was nailed down. Let’s assume it’s not.  
> 
> Then we have:
> 
> abstract class Object { }
> abstract class RefObject <: Object { }
> abstract class ValObject <: Object { }
> 
> Existing classes that extend Object are silently reparented to RefObject, 
> both at compile time and runtime.  This may have some small .getSuperclass() 
> anomalies but this seems pretty minor.  Same with anon classes of Object.  
> Inline classes implicitly extend ValObject.  
> 
> We add a method `Object::newInstance` (name to be bikeshod later.). We start 
> warning in the compiler on `new Object`, to motivate migration to 
> `Object::newInstance`.  Runtime rewrites these too.  
> 
> There are some minor behavioral compatibility issues here, but they seem 
> pretty minor, and in the end, we end up with a hierarchy that describes the 
> way we want users to see the type system.  
> 
> 



Re: RefObject and ValObject

2019-04-15 Thread John Rose
Avoid the Bikeshed!  Make sure that temporary or provisional
syntaxes look __Different from permanent ones.

On Apr 15, 2019, at 8:03 AM, Remi Forax  wrote:
> 
> val, ref and any only applies to Object.
> 
> if you prefer in term of notation, let's rename ref Object to Object?, val 
> Object to Object! and any Object to Object*,
> 
> you can apply ? on any value type, Object included,
> you can apply ! and * only on Object.



Re: RefObject and ValObject

2019-04-15 Thread Remi Forax
> De: "Brian Goetz" 
> À: "Maurizio Cimadamore" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 17:23:36
> Objet: Re: RefObject and ValObject

>> 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() { ... }`.

> After thinking about it for all of five minutes, I think this may have broken
> the logjam (or, at least the current logjam.). We’ve been asking ourselves
> whether RO/VO are classes or interfaces, when we didn’t really consider
> abstract classes. Which we didn’t consider because we had assumed that the
> concrete-ness of Object was nailed down. Let’s assume it’s not.

> Then we have:

> abstract class Object { }
> abstract class RefObject <: Object { }
> abstract class ValObject <: Object { }

> Existing classes that extend Object are silently reparented to RefObject, both
> at compile time and runtime. This may have some small .getSuperclass()
> anomalies but this seems pretty minor. Same with anon classes of Object. 
> Inline
> classes implicitly extend ValObject.

> We add a method `Object::newInstance` (name to be bikeshod later.). We start
> warning in the compiler on `new Object`, to motivate migration to
> `Object::newInstance`. Runtime rewrites these too.

> There are some minor behavioral compatibility issues here, but they seem 
> pretty
> minor, and in the end, we end up with a hierarchy that describes the way we
> want users to see the type system.

It's not a minor change, and all code that uses a type parameter that have 
Object as bound will become ambiguous. 

Rémi 


Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> For (2) the proposal I saw earlier said something like, we'd like for `new 
> Object` to mean REFERENCE. I think that is a siren song, and this issue has 
> been addressed by Brian's proposal to deal with `new Object` as a migration 
> problem. Rather than suggesting to use some static factory instead (which 
> works for plain instance creation but not for inner class creation) I think 
> perhaps the user code should be migrated to use `new RefObject` and `new 
> RefObject() { }` instead (at least if people want the reference semantics). 
> But these are minor details
> 

What I like about treating this as a migration problem is, that despite the 
inconvenience, the resulting code is actually _a lot more clear_.  The first 
time I saw “new Object()” (that was a long time ago), I remember thinking “What 
the heck is the point of that?”, until I realized that Objects had a secret 
object identity.  Whereas “new IdentityObject()” is more clear that you are 
creating an instance _for the precise purpose of using its identity_.  

So, while there is some migration pain, the resulting language is actually more 
clear.  I like that.




Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
Please, no.



> On Apr 15, 2019, at 11:03 AM, Remi Forax  wrote:
> 
> 
> 
> De: "Brian Goetz" 
> À: "Maurizio Cimadamore" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 16:38:58
> Objet: Re: RefObject and ValObject
> 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
> 
> 
> We explored this sort of thing in Q world.  One place where this really was 
> painful was what it did to generic tvar constraints; we had an entire new 
> algebra of constraints: 
> 
>  void m(T t) { … }
> 
> Brian,
> val, ref and any only applies to Object.
> 
> if you prefer in term of notation, let's rename ref Object to Object?, val 
> Object to Object! and any Object to Object*,
> 
> you can apply ? on any value type, Object included,
> you can apply ! and * only on Object.
> 
> Object? is erased to Ljava/lang/Object; by the generic signature is 
> Ljava/lang/Object/* (so it's Object for the VM and Object! for the compiler),
> Object! is erased to Qjav/lang/Object;
> Object* is erased to Ljava/lang/Object;
> 
> As a bound of a type variable, Object is equivalent to Object? by backward 
> compatibility.
> and
>void m(T t) { … }
> means that T is not nullable, so it's a value type.
> 
> And at runtime, instead of
>(o instanceof Object!)
> one will write
>   o.getClass().isValue()
> 
> Rémi
> 
> 
> which was ad hoc and composed terribly.  This hell is _exactly_ the thing 
> that pushed us to Ref/ValObject as _types_ in the first place.  (More of the 
> same: what is “ref Object”.class, and how does it differ from “any 
> Object”.class?).  
> 
> 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.
> 
> Right.  Q-world tried it the other way, and we were in utter migration hell.  
> There are migration cases in this direction too, but we are convinced they 
> are orders of magnitude fewer.  
> 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`.
> 
> Yes, this is the cost.  I have to think that given a choice between some 
> weirdness around ’new Object’, and dramatic, awful new kinds of types that 
> complicate type uses, type descriptors, reflection, etc, etc, etc, that 
> making the former work is going to be less painful, both for us and for users.
> 
> 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() { ... }`.
> 
> 
> Right.  And, again, this can be treated as a migration issue, and we can 
> start warning users to migrate their source now. 



Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> 
> 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() { ... }`.

After thinking about it for all of five minutes, I think this may have broken 
the logjam (or, at least the current logjam.). We’ve been asking ourselves 
whether RO/VO are classes or interfaces, when we didn’t really consider 
abstract classes.  Which we didn’t consider because we had assumed that the 
concrete-ness of Object was nailed down. Let’s assume it’s not.  

Then we have:

abstract class Object { }
abstract class RefObject <: Object { }
abstract class ValObject <: Object { }

Existing classes that extend Object are silently reparented to RefObject, both 
at compile time and runtime.  This may have some small .getSuperclass() 
anomalies but this seems pretty minor.  Same with anon classes of Object.  
Inline classes implicitly extend ValObject.  

We add a method `Object::newInstance` (name to be bikeshod later.). We start 
warning in the compiler on `new Object`, to motivate migration to 
`Object::newInstance`.  Runtime rewrites these too.  

There are some minor behavioral compatibility issues here, but they seem pretty 
minor, and in the end, we end up with a hierarchy that describes the way we 
want users to see the type system.  




Re: RefObject and ValObject

2019-04-15 Thread Remi Forax
> De: "Brian Goetz" 
> À: "Maurizio Cimadamore" 
> Cc: "valhalla-spec-experts" 
> Envoyé: Lundi 15 Avril 2019 16:38:58
> Objet: Re: RefObject and ValObject

>> 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

> We explored this sort of thing in Q world. One place where this really was
> painful was what it did to generic tvar constraints; we had an entire new
> algebra of constraints:

>  void m(T t) { … }

Brian, 
val, ref and any only applies to Object. 

if you prefer in term of notation, let's rename ref Object to Object?, val 
Object to Object! and any Object to Object*, 

you can apply ? on any value type, Object included, 
you can apply ! and * only on Object. 

Object? is erased to Ljava/lang/Object; by the generic signature is 
Ljava/lang/Object/* (so it's Object for the VM and Object! for the compiler), 
Object! is erased to Qjav/lang/Object; 
Object* is erased to Ljava/lang/Object; 

As a bound of a type variable, Object is equivalent to Object? by backward 
compatibility. 
and 
 void m(T t) { … } 
means that T is not nullable, so it's a value type. 

And at runtime, instead of 
(o instanceof Object!) 
one will write 
o.getClass().isValue() 

Rémi 

> which was ad hoc and composed terribly. This hell is _exactly_ the thing that
> pushed us to Ref/ValObject as _types_ in the first place. (More of the same:
> what is “ref Object”.class, and how does it differ from “any Object”.class?).

>> 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.

> Right. Q-world tried it the other way, and we were in utter migration hell.
> There are migration cases in this direction too, but we are convinced they are
> orders of magnitude fewer.

>> 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`.

> Yes, this is the cost. I have to think that given a choice between some
> weirdness around ’new Object’, and dramatic, awful new kinds of types that
> complicate type uses, type descriptors, reflection, etc, etc, etc, that making
> the former work is going to be less painful, both for us and for users.

>> 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() { ... }`.

> Right. And, again, this can be treated as a migration issue, and we can start
> warning users to migrate their source now.


Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> 
> Well, not quite. The choice is between treating 'new Object' specially or 
> not. If it's not treated specially there is no new scary type. It's just 
> that`new Object` might not have the properties one might hope for (but again, 
> those same properties would be lost as soon as you touch the result of the 
> expression).

OK, but let’s not lose sight of the fact that “new Object()” is not so much a 
language _feature_, as much as an accidental convention that people have 
settled on for accomplishing a very specific thing.  In a way, it’s like the 
so-called-but-not-really-a-feature double-brace idiom; it’s an accidental 
consequence of how the language works, that people have come to use because 
it’s convenient. 

I would much rather spend our complexity budget migrating uses of this idiom 
away and get a simpler type system, than the other way around.




Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore



On 15/04/2019 15:38, Brian Goetz wrote:


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



We explored this sort of thing in Q world.  One place where this 
really was painful was what it did to generic tvar constraints; we had 
an entire new algebra of constraints:


     void m(T t) { … }

which was ad hoc and composed terribly.  This hell is _exactly_ the 
thing that pushed us to Ref/ValObject as _types_ in the first place. 
 (More of the same: what is “ref Object”.class, and how does it differ 
from “any Object”.class?).
This is not a language proposal (as stated in the email). Just a way to 
be clearer about semantics, w/o appealing to subclasses and type 
hierarchies (which are, at this point, IMHO confusing).



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.


Right.  Q-world tried it the other way, and we were in utter migration 
hell.  There are migration cases in this direction too, but we are 
convinced they are orders of magnitude fewer.


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`.


Yes, this is the cost.  I have to think that given a choice between 
some weirdness around ’new Object’, and dramatic, awful new kinds of 
types that complicate type uses, type descriptors, reflection, etc, 
etc, etc, that making the former work is going to be less painful, 
both for us and for users.


Well, not quite. The choice is between treating 'new Object' specially 
or not. If it's not treated specially there is no new scary type. It's 
just that`new Object` might not have the properties one might hope for 
(but again, those same properties would be lost as soon as you touch the 
result of the expression).


I think you took my type modifiers too literally (as if, I'm proposing 
to add them, which I'm not) :-)


Maurizio



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() { 
... }`.




Right.  And, again, this can be treated as a migration issue, and we 
can start warning users to migrate their source now.







Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz
> 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
> 

We explored this sort of thing in Q world.  One place where this really was 
painful was what it did to generic tvar constraints; we had an entire new 
algebra of constraints: 

 void m(T t) { … }

which was ad hoc and composed terribly.  This hell is _exactly_ the thing that 
pushed us to Ref/ValObject as _types_ in the first place.  (More of the same: 
what is “ref Object”.class, and how does it differ from “any Object”.class?).  

> 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.
> 
Right.  Q-world tried it the other way, and we were in utter migration hell.  
There are migration cases in this direction too, but we are convinced they are 
orders of magnitude fewer.  
> 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`.
> 
Yes, this is the cost.  I have to think that given a choice between some 
weirdness around ’new Object’, and dramatic, awful new kinds of types that 
complicate type uses, type descriptors, reflection, etc, etc, etc, that making 
the former work is going to be less painful, both for us and for users.

> 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() { ... }`.
> 

Right.  And, again, this can be treated as a migration issue, and we can start 
warning users to migrate their source now. 






Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore
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 { }


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.




Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz


> 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 { }


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.  




Re: RefObject and ValObject

2019-04-15 Thread Remi Forax
- Mail original -
> De: "Maurizio Cimadamore" 
> À: "Brian Goetz" , "valhalla-spec-experts" 
> 
> Envoyé: Lundi 15 Avril 2019 14:20:35
> Objet: Re: RefObject and ValObject

> On 15/04/2019 13:06, Brian Goetz wrote:
>>
>>
>>> But it seems like we have already ruled this out - since, if
>>> typeof(new Object()) is 'RefObject', you don't want RefObject <: Object.
>>
>> I think you misunderstood the "want" here (though it still may not be
>> possible.)
>>
>> The desired model is:
>>  - Object is the top type.  Everything is an Object.
>>  - Some objects have identity (RefObject), others do not (ValObject).
>> But they are all Object.
>>
>> This means we want {Ref,Val}Object <: Object.  (Whether they are
>> interface or class or something else.)
> 
> Seems like I've read this requirement:
> 
> "but we don’t want Object <: RefObject for obvious reasons"
> 
> backwards. So, what this means is that it would be type-sound regardless
> of interface vs. class choice. 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.

yes,
divorcing the runtime class from the type is something we can do, but it's not 
because we can do that we should,
as a teacher you usually don't want to talk about the difference between a 
class and a type until you have reached the subtyping chapter.

The initial goal is to make the concept of ref type and value type easier to 
grasp by providing a simple hierarchy, but new Object() can not be retconed to 
a RefObject easily, so it's not that simple.

And Ruby has tried to do something similar by introducing BasicObject in 1.9 
(for another reason, because scopes are liked to classes in Ruby), at the end 
few people cares, so we have to be careful to not introduce something that will 
be a hurdle in compatibility for in the end no benefit.

So we need to be able to have types representing any Object, ref Object and 
value Object, but i think that RefObject and ValObject are not the only 
solution for that.

> 
> Maurizio

Rémi

> 
>>
>> One of the main reasons for wanting this setup is that it reflects the
>> desired reality: everything is an object, but some are special objects
>> (those with identity.)  The addition of value types is a big
>> perturbation to the type system; reflecting it this way makes the
>> object hierarchy reflect the reality and the desired intuition, and
>> makes the distinction between ref/val slightly less magic.
>>
>> (There are other reasons too; for example, wouldn't it be nice if
>> ValObject.{wait,notify,notifyAll} were _ordinary final methods_ that
>> threw in ValObject?  Again, slightly less magic.)
>>


Re: RefObject and ValObject

2019-04-15 Thread Maurizio Cimadamore



On 15/04/2019 13:06, Brian Goetz wrote:



But it seems like we have already ruled this out - since, if 
typeof(new Object()) is 'RefObject', you don't want RefObject <: Object.


I think you misunderstood the "want" here (though it still may not be 
possible.)


The desired model is:
 - Object is the top type.  Everything is an Object.
 - Some objects have identity (RefObject), others do not (ValObject).  
But they are all Object.


This means we want {Ref,Val}Object <: Object.  (Whether they are 
interface or class or something else.)


Seems like I've read this requirement:

"but we don’t want Object <: RefObject for obvious reasons"

backwards. So, what this means is that it would be type-sound regardless 
of interface vs. class choice. 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.


Maurizio



One of the main reasons for wanting this setup is that it reflects the 
desired reality: everything is an object, but some are special objects 
(those with identity.)  The addition of value types is a big 
perturbation to the type system; reflecting it this way makes the 
object hierarchy reflect the reality and the desired intuition, and 
makes the distinction between ref/val slightly less magic.


(There are other reasons too; for example, wouldn't it be nice if 
ValObject.{wait,notify,notifyAll} were _ordinary final methods_ that 
threw in ValObject?  Again, slightly less magic.)





Re: RefObject and ValObject

2019-04-15 Thread Brian Goetz




But it seems like we have already ruled this out - since, if 
typeof(new Object()) is 'RefObject', you don't want RefObject <: Object.


I think you misunderstood the "want" here (though it still may not be 
possible.)


The desired model is:
 - Object is the top type.  Everything is an Object.
 - Some objects have identity (RefObject), others do not (ValObject).  
But they are all Object.


This means we want {Ref,Val}Object <: Object.  (Whether they are 
interface or class or something else.)


One of the main reasons for wanting this setup is that it reflects the 
desired reality: everything is an object, but some are special objects 
(those with identity.)  The addition of value types is a big 
perturbation to the type system; reflecting it this way makes the object 
hierarchy reflect the reality and the desired intuition, and makes the 
distinction between ref/val slightly less magic.


(There are other reasons too; for example, wouldn't it be nice if 
ValObject.{wait,notify,notifyAll} were _ordinary final methods_ that 
threw in ValObject?  Again, slightly less magic.)





Re: RefObject and ValObject

2019-04-12 Thread Daniel Heidinga
My original thought had been that this would benefit new code that knew it had to do something identity-full (lock, make weak references, etc) and wanted to enforce it would never see a value.
 
The migration path adds a cherry on top.
 
--Dan
 
- Original message -From: Brian Goetz To: Daniel Heidinga Cc: valhalla-spec-experts Subject: Re: RefObject and ValObjectDate: Fri, Apr 12, 2019 11:51 AM 
High-order tradeoffs:  - Having R/VObject be classes helps from the pedagogical perspective(it paints an accurate map of the object model.)  - There were some anomalies raised that were the result of rewritingan Object supertype to RefObject, and some concerns about "all ourtables got one level deeper."  I don't really have a strong opinion onthese.  - Using interfaces is less intrusive, but less powerful.  - None of the approaches give an obvious solution for the "make me alock Object" problem.I think the useful new observation in this line of discussion is this:  - The premise of L-World is that legacy Object-consuming code can keepworking with values.  - We think that's a good thing.  - But  we also think there will be some cases where that's not agood thing, and that code will wish it had said `m(RefObject)` insteadof `m(Object)`.  [ this is the new thing ]Combining this with the migration stuff going on in a separate thread, Ithink what you're saying is you want to be able to take a method: m(Object o) { }and _migrate_ it to be m(RefObject o) { }with a forwarder @ForwardTo( m(RefObject) ) m(Object o);So that code could, eventually, be migrated to RefObject-consuming code,and all is good again.  And the JIT can see that o is a RefObject andcredibly fall back to a legacy interpretation of ACMP and locking.On 4/12/2019 11:16 AM, Daniel Heidinga wrote:> During the last EG call, I suggested there are benefits to having both RefObject and ValObject be classes rather than interfaces.>> Old code should be able work with both values and references (that's the promise of L-World after all!). New code should be able to opt into whether it wants to handle only references or values as there are APIs that may only make sense for one or the other. A good example of this is java.lang.Reference-subtypes which can't reasonably deal with values. Having RefObject in their method signatures would ensure that they're never passed a ValObject. (ie: the ctor becomes WeakReference(RefObject o) {...})>> For good or ill, interfaces are not checked by the verifier. They're passed as though they are object and the interface check is delayed until invokeinterface, etc. Using interfaces for Ref/Val Object doesn't provide verifier guarantees that the methods will never be passed the wrong type. Javac may not generate the code but the VM can't count on that being the case due to bytecode instrumentation, other compilers, etc.>> Using classes does provide a strong guarantee to the VM which will help to alleviate any costs (acmp, array access) for methods that are declared in terms of RefObject and ensures that the user is getting exactly what they asked for when they declared their method to take RefObject.>> It does leave some oddities as you mention:> * new Object() -> returns a new RefObject> * getSuperclass() for old code may return a new superclass (though this may be the case already when using instrumentation in the classfile load hook)> * others?>> though adding interfaces does as well:> * getInterfaces() would return an interface not declared in the source> * Object would need to implement RefObject for the 'new Object()` case which would mean all values implemented RefObject (yuck!)>> Letting users say what they mean and have it strongly enforced by the verifier is preferable in my view, especially as getSuperclass() issue will only apply to old code as newly compiled code will have the correct superclass in its classfile.>> --Dan>>> -"valhalla-spec-experts"  wrote: ->>> To: valhalla-spec-experts >> From: Brian Goetz>> Sent by: "valhalla-spec-experts">> Date: 04/08/2019 04:00PM>> Subject: RefObject and ValObject We never reached consensus on how to surface Ref/ValObject. Here are some places we might want to use these type names: - Parameter types / variables: we might want to restrict the domain>> of a parameter or variable to only hold a reference, or a value: void m(RefObject ro) { … } - Type bounds: we might want to restrict the instantiation of a>> generic class to only hold a reference (say, because we’re going to>> lock on it): class Foo { … } - Dynamic tests: if locking on a value is to throw, there must be a>> reasonable idiom that users can use to detect lockability without>> just trying to lock: if (x instanceof RefObject) {>> synchronized(x) { … }>> } - Ref- or Val-specific methods. This one is more vague, but its>> conceivable we may want methods on ValObject that are members of all>> values.>> There’s been three ways proposed (so far) that we 

Re: RefObject and ValObject

2019-04-12 Thread Brian Goetz

High-order tradeoffs:

 - Having R/VObject be classes helps from the pedagogical perspective 
(it paints an accurate map of the object model.)


 - There were some anomalies raised that were the result of rewriting 
an Object supertype to RefObject, and some concerns about "all our 
tables got one level deeper."  I don't really have a strong opinion on 
these.


 - Using interfaces is less intrusive, but less powerful.

 - None of the approaches give an obvious solution for the "make me a 
lock Object" problem.



I think the useful new observation in this line of discussion is this:

 - The premise of L-World is that legacy Object-consuming code can keep 
working with values.

 - We think that's a good thing.
 - But  we also think there will be some cases where that's not a 
good thing, and that code will wish it had said `m(RefObject)` instead 
of `m(Object)`.  [ this is the new thing ]


Combining this with the migration stuff going on in a separate thread, I 
think what you're saying is you want to be able to take a method:


    m(Object o) { }

and _migrate_ it to be

    m(RefObject o) { }

with a forwarder

    @ForwardTo( m(RefObject) )
    m(Object o);

So that code could, eventually, be migrated to RefObject-consuming code, 
and all is good again.  And the JIT can see that o is a RefObject and 
credibly fall back to a legacy interpretation of ACMP and locking.






On 4/12/2019 11:16 AM, Daniel Heidinga wrote:

During the last EG call, I suggested there are benefits to having both 
RefObject and ValObject be classes rather than interfaces.

Old code should be able work with both values and references (that's the 
promise of L-World after all!). New code should be able to opt into whether it 
wants to handle only references or values as there are APIs that may only make 
sense for one or the other. A good example of this is 
java.lang.Reference-subtypes which can't reasonably deal with values. Having 
RefObject in their method signatures would ensure that they're never passed a 
ValObject. (ie: the ctor becomes WeakReference(RefObject o) {...})

For good or ill, interfaces are not checked by the verifier. They're passed as 
though they are object and the interface check is delayed until 
invokeinterface, etc. Using interfaces for Ref/Val Object doesn't provide 
verifier guarantees that the methods will never be passed the wrong type. Javac 
may not generate the code but the VM can't count on that being the case due to 
bytecode instrumentation, other compilers, etc.

Using classes does provide a strong guarantee to the VM which will help to 
alleviate any costs (acmp, array access) for methods that are declared in terms 
of RefObject and ensures that the user is getting exactly what they asked for 
when they declared their method to take RefObject.

It does leave some oddities as you mention:
* new Object() -> returns a new RefObject
* getSuperclass() for old code may return a new superclass (though this may be 
the case already when using instrumentation in the classfile load hook)
* others?

though adding interfaces does as well:
* getInterfaces() would return an interface not declared in the source
* Object would need to implement RefObject for the 'new Object()` case which 
would mean all values implemented RefObject (yuck!)

Letting users say what they mean and have it strongly enforced by the verifier 
is preferable in my view, especially as getSuperclass() issue will only apply 
to old code as newly compiled code will have the correct superclass in its 
classfile.

--Dan


-"valhalla-spec-experts"  
wrote: -


To: valhalla-spec-experts 
From: Brian Goetz
Sent by: "valhalla-spec-experts"
Date: 04/08/2019 04:00PM
Subject: RefObject and ValObject

We never reached consensus on how to surface Ref/ValObject.

Here are some places we might want to use these type names:

- Parameter types / variables: we might want to restrict the domain
of a parameter or variable to only hold a reference, or a value:

void m(RefObject ro) { … }

- Type bounds: we might want to restrict the instantiation of a
generic class to only hold a reference (say, because we’re going to
lock on it):

class Foo { … }

- Dynamic tests: if locking on a value is to throw, there must be a
reasonable idiom that users can use to detect lockability without
just trying to lock:

if (x instanceof RefObject) {
synchronized(x) { … }
}

- Ref- or Val-specific methods. This one is more vague, but its
conceivable we may want methods on ValObject that are members of all
values.


There’s been three ways proposed (so far) that we might reflect these
as top types:

- RefObject and ValObject are (somewhat special) classes. We spell
(at least in the class file) “value class” as “class X extends
ValObject”. We implicitly rewrite reference classes at runtime that
extend Object to extend RefObject instead. This has obvious
pedagogical value, but there are some (small) risks of anomalies.

- RefObject and ValObject are interfaces. 

Re: RefObject and ValObject

2019-04-08 Thread John Rose
Yes, that's a nice one.

On Apr 8, 2019, at 1:24 PM, Brian Goetz  wrote:
> 
> Sergey pointed out this additional benefit of RefObject: code that really 
> doesn’t want to deal with values, or pay any of the taxes that arise from the 
> fact that values are Object, such as acmp overhead.