RFC: draft API for JEP 269 Convenience Collection Factories

Stuart Marks stuart.marks at oracle.com
Sat Oct 17 17:23:53 UTC 2015


On 10/14/15 5:56 AM, Ivan Gerasimov wrote:
>          Map<Integer,Character> m1 = MyCollections.<Integer,Character>
>                   ofKeys( 1,   2,   3,   4,   5)
>                  .vals(  'a', 'b', 'c', 'd', 'e');

Yes, we considered a bunch of different alternatives.

It looks like you're wrestling a bit with type inference :-), given that you had 
to invoke this with a type witness. The issue here is that the target type 
doesn't back-propagate through the chained method call .vals() to the call of 
.ofKeys(). Incidentally, a similar problem occurs in the "obvious" builder 
approach of doing something like this:

     Map<Integer,Character> map = Map.builder()
        .add(1, 'a')
        .add(2, 'b')
        ....
        .build();

It's possible to pursue workarounds for this problem, but then you're heading 
down the rabbit hole....

A quasi-syntactic issue is that it's preferable to have each key and value next 
to each other, so that each pair can be on its own line. This makes it easier to 
maintain. If all the keys are listed together first, followed by all the values, 
the pairing can only be made to work if they're all short and if there are few 
enough pairs (as in your example). Things start to break down if the keys/values 
themselves are long, or if there are a lot of them, pushing the keys and values 
lists onto multiple lines. Consider my example from the head of the thread:

     Map<String,TypeUse> m = Map.ofEntries(
         entry("CDATA",       CBuiltinLeafInfo.NORMALIZED_STRING),
         entry("ENTITY",      CBuiltinLeafInfo.TOKEN),
         entry("ENTITIES",    CBuiltinLeafInfo.STRING.makeCollection()),
         entry("ENUMERATION", CBuiltinLeafInfo.STRING.makeCollection()),
         entry("NMTOKEN",     CBuiltinLeafInfo.TOKEN),
         entry("NMTOKENS",    CBuiltinLeafInfo.STRING.makeCollection()),
         entry("ID",          CBuiltinLeafInfo.ID),
         entry("IDREF",       CBuiltinLeafInfo.IDREF),
         entry("IDREFS",
                   TypeUseFactory.makeCollection(CBuiltinLeafInfo.IDREF));
         entry("ENUMERATION", CBuiltinLeafInfo.TOKEN));

Maintaining the association between keys and values is challenge. Here's my 
attempt, where keys and values are associated by indentation level:

     Map<String,TypeUse> m = Map.<String,TypeUse>
          ofKeys("CDATA",
                   "ENTITY",
                     "ENTITIES",
                       "ENUMERATION",
                         "NMTOKEN",
                           "NMTOKENS",
                             "ID",
                               "IDREF",
                                 "IDREFS",
                                   "ENUMERATION")
         .vals(  CBuiltinLeafInfo.NORMALIZED_STRING,
                   CBuiltinLeafInfo.TOKEN,
                     CBuiltinLeafInfo.STRING.makeCollection(),
                       CBuiltinLeafInfo.STRING.makeCollection(),
                         CBuiltinLeafInfo.TOKEN,
                           CBuiltinLeafInfo.STRING.makeCollection(),
                             CBuiltinLeafInfo.ID,
                               CBuiltinLeafInfo.IDREF),
 
TypeUseFactory.makeCollection(CBuiltinLeafInfo.IDREF),
                                   CBuiltinLeafInfo.TOKEN);

With more pairs, the distance between each key and its corresponding value also 
increases. You could try to reduce the vertical distance by filling the lines 
(more keys/values per line) but that makes the association challenges even 
harder. Finally, consider the pain of inserting or removing a key/value pair 
from the middle.

s'marks



More information about the core-libs-dev mailing list