Indexing access for Lists and Maps considered harmful?
Reinier Zwitserloot
reinier at zwitserloot.com
Tue Jun 23 21:38:59 PDT 2009
It's not just a matter of figuring out "what interfaces we need to
make this work" - at least, with Neal's semantics. I'm making the
assumption that "a[x] = b" should be legal where x is an integer, a is
a java.util.List<T>, and b is a T. That's obvious - that's the goal of
this proposal in the first place. Neal's semantics and the way
java.util.List is designed makes it impossible to address this issue
by way of an interface. You'd need to hardcode the meaning of a[b] = c
for at least java.util.List, if you want Neal's semantics.
At the same time, Neal's semantics, while almost impossible to
implement, are essentially correct, in that they are the most
compatible of all the various proposals with how pass-through
assignment works today in java6.
Conclusion: I think we need to move away from being 100% consistent in
an area (pass-through assignment) that almost nobody uses. It's not
worth either complicating the proposal or delaying it, just to get to
this mythical 100% consistency, especially considering that we can
always add it later if we roll with 'a[b] = c is not an expression but
a statement, when it involves SetIndex desugaring' now.
--Reinier Zwitserloot
On 2009/24/06, at 05:40, Joshua Bloch wrote:
> Reinier,
>
> I don't really understand your post. What's wrong with just
> agreeing at the outset that a[i] = b[i] = x; works, and then
> figuring out what (if any) interfaces we need to make it work?
>
> Josh
>
> On Tue, Jun 23, 2009 at 6:39 PM, Reinier Zwitserloot <reinier at zwitserloot.com
> > wrote:
> I agree to the theory of your post, but, so what?
>
> Java is not going to be perfect unless java is willing to sacrifice
> backwards compatibility, which it isn't. So, perfection can't be the
> goal - because if it is, then no language change is ever going to make
> it in, and paradoxically, that really brings java no closer to
> perfection.
>
> So - so what that it isn't perfect? Let's roll with where I think you
> are trying to go, and create 2 interfaces, where the SetIndex
> semantics are defined as requiring the implementing class to return
> the logical value - e.g. boxing a primitive when assigning it into a
> list, for example.
>
> But now we can't retrofit java.util.List without breaking thousands of
> List implementations out there, so the conclusion would have to be
> that you can not use a List itself; you must use either a specific
> type (such as ArrayList, retrofitted to implement SetIndex), or a
> newly created List2 interface that also implements SetIndex. In this
> scenario, I'm assuming the name of the method isn't set(), as that
> would conflict with java.util.List's set which has different
> semantics.
>
> So, riddle me this then. There are 3 java7 scenarios:
>
> In the first scenario, m[a] = m[b] = c; does what you want, but only
> if m is an ArrayList, SetIndex, or HashMap. It just doesn't work if m
> is a List or Map type. Even for just "m[b] = c", which I'll bet is
> more prevalent than m[a] = m[b] = c by a factor of 100 or more!
>
> In the second scenario, m[a] = m[b] = c does not do what you want (and
> in my opinion, should express this by failing fast - generating a
> compiler error on the spot stating that m[b] = c is not an expression,
> but that's not relevant to the point I'm trying to make here) - but it
> works with every type you'd expect it to work with: List, Map, arrays,
> and many other types of objects.
>
> In the third scenario, m[a] = c isn't allowed at all.
>
> In the fourth scenario, java complicates the process quite a bit e.g.
> by having a scala-esque conversion semantic where some class in the
> classpath has registered itself as capable of turning any
> java.util.List into a java.lang.SetIndex object. m[a] = m[b] =c does
> what you want, and it works with List, but now the proposal is rather
> complicated.
>
> I'm quite certain the (vast?) majority will go with the second java7.
> If pass-through assignment was more common than it is, it might be
> worth investigating the fourth scenario more thoroughly,
>
> NB: I'd hereby like to repeat my suggestion to choose pragmatism over
> perfection here: Returning void is pragmatic, in that we can always
> change it later without breaking any code. In this case, the pragmatic
> choice may have to be to define explicitly SetIndex behaviour as
> existing for java.util.List and java.util.Map and no other types of
> objects (hard code the types, at least for now - no need to do this to
> GetIndex, as there are no issues there). If these things are sorted
> out in the future, then the restriction can be waived, and any code
> can use it. It may not be /pretty/, but it has the crucial advantage
> of being future-compatible!
>
> --Reinier Zwitserloot
>
>
>
> On 2009/24/06, at 02:47, Neal Gafter wrote:
>
> > These methods are language-support methods. If I create a new
> array-
> > like
> > API, what should its "put" method return? Four choices are void,
> > null, the
> > input value, or the logical value placed into the data structure.
> >
> > void doesn't work because that's not the return type of the method
> > in these
> > interfaces.
> >
> > null is silly (an API method that should always return nothing
> > should be
> > declared void), and conflicts with the JLS's meaning of an
> assignment
> > expression (see below).
> >
> > The input value isn't correct; the value resulting from the
> > assignment is
> > supposed to be the NEW value in that variable (JLS3 15.26 paragraph
> > 3). For
> > built-in arrays, that is the value converted to the array element
> > type.
> >
> > For general collection-like APIs, the result of an assignment using
> > the
> > array syntax may be some other "equivalent" value (for example,
> > strings
> > might be interned). To support the JLS semantics, the API needs to
> > have an
> > opportunity to yield this value. So IndexedAccess<V>.put() should
> be
> > declared to return a value of type V, which should be specified to
> > be *the
> > value of the logical variable after the assignment has occurred*.
> > java.util.List, on the other hand, has a put method that is declared
> > with
> > the right signature (it returns a V), but it returns the wrong value
> > to
> > support the JLS semantics for assignment.
> >
> > Retrofitting interfaces onto existing classes is a poor solution to
> > this
> > language-design problem.
> >
> > Regards,
> > Neal
> >
> > On Tue, Jun 23, 2009 at 4:35 PM, Shams Mahmood <shams.mahmood at gmail.com
> > >wrote:
> >
> >> I don't follow why it won't handle anything other than the
> >> collections api.
> >> The compiler should be able to support any implementations of
> >> IndexedAccess<V> and DictionaryAccess<K, V> just like the for each
> >> loop
> >> handles any implementations of the Iterable interface.
> >>
> >>
> >>
> >> ------------------------------
> >> *From:* Neal Gafter <neal at gafter.com>
> >> *To:* Shams Mahmood <shams.mahmood at gmail.com>
> >> *Cc:* coin-dev at openjdk.java.net
> >> *Sent:* Tuesday, June 23, 2009 4:42:40 PM
> >> *Subject:* Re: Indexing access for Lists and Maps considered
> harmful?
> >>
> >> On Tue, Jun 23, 2009 at 1:55 PM, Shams Mahmood <shams.mahmood at gmail.com
> >> >wrote:
> >>
> >>> So,
> >>> List<String> list = new ArrayList();
> >>> list[1] = list[0] = "value";
> >>> would get translated to:
> >>> Collections.set(list, 1, Collections.set(list, 0, "value"))
> >>
> >>
> >> The link to methods in Collections is a bit too magical (e.g. it
> >> won't
> >> gracefully handle anything other than the collections API nor
> will it
> >> gracefully support evolution of the platform).
> >>
> >>
> >>
> >
>
>
>
More information about the coin-dev
mailing list