Factory methods for SequencedSet and SequencedMap
Joseph D. Darcy
joe.darcy at oracle.com
Sat Jan 18 01:14:32 UTC 2025
On 1/17/2025 5:00 PM, David Alayachew wrote:
>
> Thanks for the corrections folks. I was thinking from the perspective
> of LSP. I now see that there is the performance perspective to
> consider too.
>
> Now that said, I don't understand your comment Joe Darcy. Could you
> explain it in more detail?
>
Say you compile your code against JDK 24 and use the 1-argument Set.Of()
method. For that call site, your class file will refer to a method using
information akin to
"In the class java.util.Set, a method named "of" that *returns a
java.util.Set* and take a java.lang.Object as an argument"
(The generic information is basically erased in the class file, hence
Set rather than Set<E> and Object rather than E.)
If we were then in JDK 25 to replace in java.util.Set
static <E> Set<E> of(E e1){...}
with
static <E> SequencedSet<E> of(E e1){...}
when your class file ran against JDK 25, there would be no method
"In the class java.util.Set, a method named "of" that *returns a
java.util.Set* and take a java.lang.Object as an argument"
for your class to call and the linkage would fail.
For static methods, the change is equivalent to removing a method and
adding back a different, same-named method.
HTH,
-Joe
> My initial pick up of your comment is that, the parameter types and
> the return types of a method must match the types exactly between
> releases, otherwise there are no bridge methods FOR STATIC TYPES. But
> as for why, I don't understand.
>
> I know that static methods are not so much inherited as they are just
> given as is (hence why there is not really a static abstract method).
> But I don't quite see the line connecting that with no bridge methods
> for static. Maybe I don't understand bridge methods well enough.
>
>
> On Fri, Jan 17, 2025, 12:32 PM Joseph D. Darcy <joe.darcy at oracle.com>
> wrote:
>
> On 1/16/2025 11:26 PM, Rafael Winterhalter wrote:
>> Would it even be possible to change the return types of
>> Set.of(...) and Map.of(...) without breaking binary compatibility?
>
>
> In short, no.
>
> The methods in question are *static* methods. Switching to
> covariant overrides with more precise return types works for
> subclasses because of bridge methods.
>
> In a bit more detail, in a covariant override a single method in
> the source code gets translated into multiply methods in the class
> file. References to methods in the class file use the argument
> types and return type so if an old class file refers to the
> previously declared source-level return type, there is the bridge
> method present to be linked to (for binary compatibility) and then
> executed.
>
> -Joe
>
>
>>
>> I also think that the randomization of Set.of(...) and
>> Map.of(...) is a good property as it uncovers bugs early if one
>> relies on iteration order. This especially since those methods
>> are often used in tests where production code would use a proper
>> HashSet which cannot guarantee iteration order for good reasons.
>> Exactly here I think the new interfaces are a good addition as it
>> uncovers such misconceptions. If code relies on insertion order,
>> providing a Set.of(...) does no longer compile, what is a good thing.
>>
>> To me, adding SequencedSet.of(...) and SequencedMap.of(...)
>> sounds like the right approach, with implementations similar to
>> that of Set.of(...) and Map.of(...). As for megamorphism, I think
>> the chance of encounter at a call site is similar, as Set12 and
>> SetN from the Set interface are typically combined with HashMap.
>> As for a possible SequencedSet12 and SequencedSetN, I think they
>> would normally be seen with LinkedHashSet.
>>
>> Best regards, Rafael
>>
>> Am Fr., 17. Jan. 2025 um 00:36 Uhr schrieb David Alayachew
>> <davidalayachew at gmail.com>:
>>
>> I should also add, the documentation went out of their way to
>> specify that iteration order is unspecified.
>>
>> Also, I see Rémi's comment, but that's even more unconvincing
>> to me.
>>
>> Map.of has an upper limit of 10 entries, and Map.ofEntries
>> has an upper limit of that Java max file size limit thing.
>> You all know what I am talking about.
>>
>> Point is, both of these static factories were meant to be
>> used on a small number of entries. If it truly has just been
>> not done until now, then the bug database will confirm that
>> easily.
>>
>> When I get back, I can check myself.
>>
>>
>> On Thu, Jan 16, 2025, 6:25 PM David Alayachew
>> <davidalayachew at gmail.com> wrote:
>>
>> I guess let me ask the obvious question.
>>
>> Chesterton's fence -- why wasn't this done before? I
>> refuse to believe that this idea wasn't thought up years
>> ago, which leads me to believe there was a reason that it
>> hasn't been done.
>>
>> Is there any way we can look this up in the bug database
>> or something?
>>
>>
>> On Thu, Jan 16, 2025, 2:28 PM Jens Lideström
>> <jens at lidestrom.se> wrote:
>>
>> Having the result Map.of and Set.of preserve the
>> insertion order would
>> often be convenient.
>>
>> More often than not programs iterate over the
>> contents of a maps and
>> sets at some point. For example to present the values
>> in a GUI, for
>> serialisation, or even for error printouts. In all
>> those cases having a
>> fixed iteration order is much better than having a
>> random iteration
>> order.
>>
>> Often it is even a subtle bug to have a random
>> iteration order. For
>> example, I ran in to a situation where jdeps printed
>> a error message
>> containing a list of modules. But the list was in a
>> different order on
>> each run of the program! It took me a while to figure
>> out that it was
>> actually the same list. A possible explanation is
>> that jdeps is
>> implemented using Map.of or Set.of.
>>
>> Because of this I think I would be better if the most
>> commonly used
>> standard collection factories produced collections
>> with a fixed
>> iteration order.
>>
>> Guavas ImmutableMap and ImmutableSet also preserve
>> insertion order.
>>
>> Regards,
>> Jens Lideström
>>
>>
>> On 2025-01-16 08:44, Remi Forax wrote:
>>
>> > -------------------------
>> >
>> >> From: "Rafael Winterhalter" <rafael.wth at gmail.com>
>> >> To: "core-libs-dev" <core-libs-dev at openjdk.java.net>
>> >> Sent: Thursday, January 16, 2025 8:13:17 AM
>> >> Subject: Factory methods for SequencedSet and
>> SequencedMap
>> >
>> >> Hello,
>> >
>> > Hello,
>> >
>> >> I am happily taking SequencedSet and SequencedMap
>> into use, but one
>> >> inconvenience I encounter is the lack of factory
>> methods for the two.
>> >> In code where many (initial) collections have zero
>> or one element (for
>> >> later aggregation), I now write
>> Set.of()/Set.of(one) and
>> >> Map.of()/Map.of(key, value), as it makes the code
>> shorter and more
>> >> readable. Those collections are of course
>> implicitly sequenced, but
>> >> now I must make the variable type of the
>> surrounding monad Set and
>> >> Map, and simply assume that a LinkedHashSet or
>> LinkedHashMap is used
>> >> when a collection of more than one element is set,
>> without requiring
>> >> the interface type. This does not require any type
>> casting, as I rely
>> >> on the iteration order only, but the code loses
>> some of its
>> >> expressiveness.
>> >> I did not find any discussion around introducing
>> factories for
>> >> SequencedSet.of(...) and SequencedMap.of(...),
>> similar to those that
>> >> exist in the Set and Map interfaces. Was this ever
>> considered, and if
>> >> not, could it be?
>> >
>> > Thanks for re-starting that discussion, it was
>> talked a bit, but not as
>> > it should be.
>> >
>> > So the issue is that currently we do not have any
>> compact, unmodifiable
>> > and ordered Set/Map implementation,
>> > one use case is when you have data that comes from
>> a JSON object as a
>> > Map and you want to keep the inserted order, if by
>> example the JSON is
>> > a config file editable by a human, an other example
>> is in unit tests
>> > where you want to help the dev to read the output
>> of the test so the
>> > code that creates a Set/Map and what is outputed by
>> the test should be
>> > in the same order.
>> > Currently there is no good solution for those use
>> cases because
>> > Set|Map.copyOf() does not keep the ordering.
>> >
>> > I see two solutions, either we add a new
>> > SequenceSet|SequenceMap.of/copyOf, or we change the
>> impleemntation of
>> > Set|Map.of()/copyOf().
>> > Python had gone for the latter solution, which has
>> the advantage a
>> > being simple from the user POV, but from an
>> algorithm expert POV, a Set
>> > and a SequencedSet are different concepts we may
>> want to emphasis ?
>> >
>> >> Best regards, Rafael
>> >
>> > regards,
>> > Rémi
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20250117/ccfe8029/attachment-0001.htm>
More information about the core-libs-dev
mailing list