Indexing access for Lists and Maps considered harmful?

Reinier Zwitserloot reinier at zwitserloot.com
Tue Jun 23 18:39:18 PDT 2009


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