Factory methods for SequencedSet and SequencedMap

David Alayachew davidalayachew at gmail.com
Sat Jan 18 01:49:41 UTC 2025


It definitely helps.

I guess my next question is, there is no bridge method, which is why this
fails. Why not add a bridge method? What is stopping Java from doing this?

And to be clear, it is obvious to me that SewuencedSet.of is the right
answer. I am just trying to understand the point you raised.

On Fri, Jan 17, 2025, 8:14 PM Joseph D. Darcy <joe.darcy at oracle.com> wrote:

>
> 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/6245c702/attachment-0001.htm>


More information about the core-libs-dev mailing list