Static fields in specialized classes

Vitaly Davidovich vitalyd at gmail.com
Wed Oct 15 14:56:12 UTC 2014


>
> C# had the benefit of hindsight and designed their VM explicitly to
> support parametric polymorphism, including over value types.  We don't have
> that benefit, and we're not going to redesign the VM for generics (sorry).


For posterity, .NET gained generics in 2.0, which was about 4 yrs after
initial release.  They bit the bullet and made this first class (i.e. VM
knows about it), but granted they had fewer years of history/compatibility
(and user base) to deal with at the time.

If you conclude that List<int> is represented by a different class than
> List<String>, now we get to ask some questions.  Should I be able to
> reflect over the members of List<int>?  Should I be able to ask whether
> something is an instance of List<int>?  If so, we have a choice of how to
> spell this, but ultimately that's just a question of syntax, how we expose
> the reality into the surface language.
>

My vote/answer would be "yes" to both of those questions.  I'm not a fan of
erasure though, so I'm biased :).


>
> Whether we add more to reflection -- and we certainly will have to -- is
> another matter, but I think your actual disagreement is with the
> representation of generic types by classes.
> (Anyone else find it amusing that people complain when generics are erased
> (all instantiations are represented by a single class), and then complain
> when they are not erased (different instantiations mapped to different
> classes)?)


Yes, it's amusing but unsurprising given java's culture of preserving
backwards compatibility at all cost.  Personally, I worry that evolving the
language with too much concern for preserving 10+yr old behavior is going
to lead to clunky features.  Perhaps there can be a java X release that
simply breaks free of some baggage and people wanting to upgrade do their
part in modifying their codebase accordingly? Wishful thinking, I know :)


On Wed, Oct 15, 2014 at 10:19 AM, Brian Goetz <brian.goetz at oracle.com>
wrote:

> Let's take several steps back away from the "I want to continue
> programming with the reflective tools I was comfortable with in Java 1.0",
> and see if we can get at the heart of this "augh, different is scary!"
> reaction here that seems to be spreading.
>
> Forget for a second about whether the letters "List<int>.class" have
> semantic meaning in a .java file.  We can certainly hide that, though I
> think (as I said yesterday) you'd probably ultimately complain if we did.
>
> The fundamental question for an implementation of generics is the mapping
> between types and classes.  (List<String> is a type; List.class is a class.)
>
> In Java 1.0, there was a clean 1:1 mapping from types to classes.
>
> In Java 5, all instantiations of List<X>, for reference X, mapped to class
> List.class; this is an all-to-1 mapping.  This is simple but everyone seems
> to think this is smelly and complains about it a lot. (Too bad, this aspect
> isn't going away.)
>
> In C++ templates, there is a clean 1:1 mapping again; every instantiation
> of list<x> is a distinct class, with no relationship to each other in the
> type system.  But that distinctness means we give something up; for
> example, there is no "instanceof list" (or cast to list) because list is an
> infinite family of unrelated types.
>
> C# had the benefit of hindsight and designed their VM explicitly to
> support parametric polymorphism, including over value types.  We don't have
> that benefit, and we're not going to redesign the VM for generics (sorry).
>
> So the question is, can we implement List<int> with the same class as we
> implement List<String>.  Nearly all the other discomforts follow from this
> same issue (that's what instanceof means, for example).  Can you do
> better?  (I propose you think about this for a good long time before
> responding.)
>
> If you conclude that List<int> is represented by a different class than
> List<String>, now we get to ask some questions.  Should I be able to
> reflect over the members of List<int>?  Should I be able to ask whether
> something is an instance of List<int>?  If so, we have a choice of how to
> spell this, but ultimately that's just a question of syntax, how we expose
> the reality into the surface language.
>
> Whether we add more to reflection -- and we certainly will have to -- is
> another matter, but I think your actual disagreement is with the
> representation of generic types by classes.
>
> (Anyone else find it amusing that people complain when generics are erased
> (all instantiations are represented by a single class), and then complain
> when they are not erased (different instantiations mapped to different
> classes)?)
>
> On 10/15/2014 9:48 AM, Paul Benedict wrote:
>
>> I throw my lot in with Ben and Stephen. I don't think specialization
>> should be exposed to the point that you can tell the difference with
>> .class. That's very disruptive to code and surprising. Rather, I think
>> you should expose more methods on Class to query the specialization type
>> -- that was something I recommended in the beginning and still favor.
>>
>>
>> Cheers,
>> Paul
>>
>> On Wed, Oct 15, 2014 at 3:30 AM, Ben Lewis <benlewisj at gmail.com
>> <mailto:benlewisj at gmail.com>> wrote:
>>
>>       I think having Foo.class and Foo<int>.class be different is a
>> mistake.
>>
>>     class Person{}
>>
>>     class Employee<any T> extends Bar{
>>           //lots of other stuff irrelevant to T
>>           T getId(){ … }
>>     }
>>
>>     Person p1=new Employee<Object>();
>>     Person p2=new Employee<int>();
>>
>>     As I understand it
>>
>>     p1.class==Employee.class;//true
>>     p2.class==Employee.class;//false
>>     p1 instanceof Employee;//true
>>     p2 instanceof Employee;//false
>>
>>     How to determine b2 comes from ‘source class’ Employee?
>>
>>     This will cause bugs in situations where the programmer expects how
>> the
>>     class hierarchy acts now rather than changing it to where
>> specialisation
>>     having a different class. This would also mean migrating <T> to <any
>> T>
>>     will cause backward compatibility issues.
>>
>>     For example
>>
>>     if(p instanceof Employee){
>>         //do something
>>     }else{
>>         //do something else
>>     }
>>
>>     if written before specialisations It would do as expected but after
>>     and if
>>     p=new Employee<int>() it would execute the else block not as
>>     expected when
>>     the code is written.
>>
>>     On Wed, Oct 15, 2014 at 12:59 PM, Brian Goetz
>>     <brian.goetz at oracle.com <mailto:brian.goetz at oracle.com>>
>>
>>     wrote:
>>
>>      > My gut feeling is that this is undesirable and should be
>> disallowed,
>>      >> and that perhaps we shouldn't even be able to observe
>> Foo<int>.class
>>      >> at all.
>>      >>
>>      >
>>      > If you think about the problem a little more, I think you'll find
>>     that
>>      > this is wishful thinking.  (But of course, you're free to have a
>> gut
>>      > feeling without having thought about it at all.)
>>      >
>>      >  After all, if specialization is intended to be viewed primarily
>>     as an
>>      >> implementation detail
>>      >>
>>      >
>>      > It is an implementation detail in the same sense that erasure is;
>>     that
>>      > generics are implemented by erasure almost certainly leaks into
>>     the user's
>>      > perception too.  (Erasure is why you can't have
>>     Foo<String>.class, for
>>      > example.  Among many other things that the user has to pay
>>     attention to.)
>>      >
>>      > class Foo<any T> {
>>      >     T get() { ... }
>>      > }
>>      >
>>      > Consider the members of various instantiations of Foo.
>>      >
>>      > The signature of get() in Foo<String> is "String get()", but the
>>     signature
>>      > of get() in Foo<int> is "int get()".  The erasure of the first is
>>     "Object
>>      > get()"; the erasure of the second is "int get()".  While all erased
>>      > reference instantiations can be implemented by the same class, the
>>      > primitive/value instantiations cannot be.
>>      >
>>      > Similarly, Foo<int> can't extend Foo<?> (because that really
>>     means Foo<?
>>      > extends Object>, and has to for compatibility reasons), nor can
>>     it extend
>>      > raw Foo.  (Which is fine; raw types exist solely to support
>>     migration from
>>      > ungenerified codebases to generified ones.)
>>      >
>>      > We could hide the existence of List<int>.class, but that would
>>     just make
>>      > life harder for users, who would then have to jump through bigger
>>     hoops to
>>      > reflect over the members of List<int> (which are different from
>>     the members
>>      > of List<String>, even after erasure.)
>>      >
>>      >  In other words, while the Java language/library changes may be
>>      >> expressed by some improvements to reflection, I'd be concerned
>> about
>>      >> the many implemented algorithms based on reflection.
>>      >>
>>      >
>>      > It is of course reasonable to be concerned.  Stay tuned and see
>>     if your
>>      > concerns are addressed.
>>      >
>>
>>
>>


More information about the valhalla-dev mailing list