Idea how to implement VT/VO compatibility in JVM
Peter Levart
peter.levart at gmail.com
Thu Jan 29 06:55:16 UTC 2015
On 01/29/2015 04:58 AM, Vitaly Davidovich wrote:
> Sorry Peter, I'm having a hard time understanding what this buys us - could
> you explain what problem this solves exactly? It's certainly not for
> backcompat from the description, so unclear.
I'm just contemplating about the usefulness of a construct.
Equivalent to relation of:
<T> void m(Collection<T> c) { ... }
vs.
void m(Collection<?> c) { ... }
There could also be:
<any T> void m(Collection<T> c) { ... }
vs.
void m(Collection<any ?> c) { ... }
Although the later (any ?) is less useful than the former (?), there is
still some use to be found in the anyfied one. And the language features
should be orthogonal if at all possible.
Regards, Peter
>
> sent from my phone
> On Jan 28, 2015 4:56 PM, "Peter Levart" <peter.levart at gmail.com> wrote:
>
>> On 01/22/2015 02:26 PM, Maurizio Cimadamore wrote:
>>
>>
>> On 22/01/15 13:19, Vitaly Davidovich wrote:
>>
>> Can you expand a bit on the part where you say frameworks can't iterate a
>> Collection<any T> without knowing the instantiation? Do you mean existing
>> methods that take Collection<?> won't work without change or something
>> else?
>>
>> In the current prototype, such methods will work, but they will work with
>> all reference-parameterizations - example:
>>
>> void m(Collection<?> c) { ... }
>>
>> List<String> ls = ...
>> List<Object> lo = ...
>> List<int> li = ...
>> List<MyPointValue> lmpv = ...
>>
>> m(ls); //ok
>> m(lo); //ok
>> m(li); //fail, List<int> is not subtype of Collection<?>
>> m(lmpv); //fail, List<MyPointValue> is not subtype of Collection<?>
>>
>> In other words, Collection<?> means Collection<? extends Object>.
>> Therefore, primitives and values are outside the domain supported by the
>> unbounded wildcard.
>>
>> To fix that, you need to change 'm' as follows:
>>
>> <any T> void m2(Collection<T> c) { ... }
>>
>> m(ls); //ok
>> m(lo); //ok
>> m(li); //ok
>> m(lmpv); //ok
>>
>> Is this what you were asking?
>>
>> Maurizio
>>
>>
>> There could also be an abbreviation:
>>
>> void m3(Collection<any ?> c) { ... }
>>
>> ...which would be equivalent to m2 above, but used only if you don't need
>> T in the method (you only invoke methods on 'c' that are not mentioning T
>> from Collection<any T> in their signature, such as size(), clear(), ...).
>> Maybe you could also call methods, that mention T in return type, but you
>> could not assign the result to anything (or maybe to Object in certain
>> situations), for example:
>>
>> class Foo<any T> {
>>
>> T getOne() { ... }
>>
>> Optional<T> getMaybe() { ... }
>>
>> }
>>
>>
>> void m4(Foo<any ?> anyFoo) {
>>
>> anyFoo.getOne(); // can call, but not use the result
>>
>> Object r = anyFoo.getMaybe(); // can assign to Object since
>> Optional<?>, Optional<int>, etc. are all Objects
>>
>> }
>>
>> (I'm still considering Optional as reference type here)
>>
>> Peter
>>
>>
>>
>>
>> sent from my phone
>> On Jan 22, 2015 8:12 AM, "Stéphane Épardaud" <stef at epardaud.fr>
>> <stef at epardaud.fr> wrote:
>>
>> On 01/22/2015 12:18 PM, Maurizio Cimadamore wrote:
>>
>> I don't think there's an 'hole' as such in your proposal - but there are
>> 'unknowns'.
>>
>> Well, that's already good news. I prefer unknowns to known holes ;)
>>
>> Performance-wise, I think the 'risk' is that if we keep the API the way
>>
>> they are today (i.e. removeAll(Collection<?>) and friends), the boxing
>> path
>> will pretty much be the norm. Now, in a perfect world, as value types are
>> non-polymorphic (or their polymorphism is very restricted) and immutable,
>> that would suggest that VM should have enough of an hint to perform boxing
>> elimination and such, so that the cost you end up paying is negligible.
>> How
>> much of this is reality? As you, I'm not a VM guru - but I think it's a
>> question worth asking. It seems a likely scenario that the JVM will do
>> great in most cases, and have some bad performance cliffs in others - is
>> that something we are willing to sign up for?
>>
>> OK, that's fair. By allowing people to use value types boxed we allow
>> them
>> to shoot themselves in the foot perf-wise (assuming the VM can't help),
>> because we make value types much more accessible. This is mostly due to
>> `any T` being opt-in rather than the new default for `T` where `T extends
>> Object` is not specified. If we also changed `T` to mean `any T` (source
>> only, so for newly compiled code) then all generics code would be
>> specializable by default and that means that users of generic code will
>> always be able to use the specialised code as long as they can instantiate
>> the generic type argument at compile-time (as is already the limitation).
>> If they can't, well they already have to use `Object` and boxing and can't
>> traverse collections because they're not `List<Object>` (ATM).
>>
>> Making it the default has down sides, probably in larger class files, but
>> as long as it's not the default, there will always be incompatibilities in
>> libraries that will forget to opt-in, which will mean that either (ATM)
>> they can't be used with containers of value types, or that the containers
>> have to be wrapped to box the value types (unless we fix that as I
>> suggest). IMO that's already going to cause compatibility issues and there
>> may arise a "coding guideline" (remember them from C++ sore points?) that
>> people will be strongly encourage to use `val T` everywhere just in case
>> someone wants to use an unboxed value type.
>>
>> The rift between primitives and Object is already a famous sore point in
>> Java (not criticising, this was a choice made a long time ago, for valid
>> reasons, we just have to deal with it) which has been "fixed" in most
>> non-Java JVM-languages due to popular demand. I don't think the new
>> default
>> with value types should be that generics don't accept value types.
>>
>> On the language-side unknowns, how much code out there is relying on
>>
>> being able to access fields on Foo<?> or raw Foo types? This is perhaps
>> not
>> common, but I think we need to gather data points on this i.e. by looking
>> at existing open source projects (help welcome here!). Other possible weak
>> points are that this doesn't necessarily address all the issue w.r.t.
>> language uniformity - i.e. how is an ArrayList<int> supposed to answer to
>> a
>> question of the kind 'is instance of List<?>' ?
>>
>> Fields that don't involve the `any T` are fine. Fields that do may have
>> to
>> revert to autoboxing _if_ we feel we _must_ accomodate that to autobox not
>> just value types but their containers.
>>
>> `ArrayList<int>` is special, mostly due to the fact that I'm not sure we
>> can retrofit `Integer` to be a value type, so existing primitives may not
>> get the `List<int> === List<Integer>` that I suggest for value types
>> (though I'd be very interested in making this work).
>>
>> If we take an easier example assuming a value type named `Date`, then yes
>> I expect that:
>>
>> - `List<val Date> instanceof List<?>` == `true`
>> - `List<__Boxed Date> instanceof List<?>` == `true`
>>
>> I'm not denying there's something there worth exploring (as I have in
>>
>> fact already said), but it seems to me that, while you can go a long way
>> with bridges, there are still questions that bridges alone simply do not
>> have an answer for.
>>
>> Thanks, and yes I agree there are still questions remaining, and more
>> importantly an implementation lacking, but hopefully if the proposal
>> sounds
>> decent I can help with the proto.
>>
>> Thanks for your answers BTW :)
>>
>>
>>
>>
More information about the valhalla-dev
mailing list