RFR(m): 8177290 add copy factory methods for unmodifiable List, Set, Map

John Rose john.r.rose at oracle.com
Sat Nov 18 06:40:05 UTC 2017


On Nov 3, 2017, at 1:26 AM, Patrick Reinhart <patrick at reini.net> wrote:
> 
>> 
>> On 11/1/2017 4:29 PM, Patrick Reinhart wrote:
>>> In this case I would prefer a non static copyOf() method on the list
>>> to create a unmodifiable list/set/map, where the optimal factory
>>> method can be called. This would also solve the problem of a
>>> concurrent implementation.

Such methods would, unfortunately, be a disastrous mistake.

We are encouraging users to rely on the unmodifiability of the
value-based lists, sets, and maps returned by copyOf, the
same way they rely on the unmodifiability of Strings.  But
if we made copyOf be non-static, then an attacker (or just
a buggy program) could introduce a broken implementation
of List that returned a time-varying List.  This would break
the contract of copyOf, but it would be impossible to detect.
The result would be a less reliable copyOf API, and
eventually some TOCTTOU security vulnerabilities.
This kind of surprise mutability is red meat for security
researchers.

So it's got to be a static method, although if List were a
class we could also choose to make copyOf be a final method.

I said "unfortunately" above because I too would prefer
fluent syntax like ls.unmodifiableCopy() or ls.frozen()
instead of List.copyOf(ls), since fluent syntax reads
and composes cleanly from left to right.

I think a good way to get what we want may be to
introduce a way for selected methods of an interface
to mark themselves (somehow) as "fluent statics",
meaning that they can be invoked with their first
argument in receiver position, before the dot.
In effect, they would act like "final default" methods
but without having to damage interfaces with final
methods.

I don't have a syntax in mind for defining a "fluent
static", but I have thought for some time that allowing
such sugar for interface statics is the best way to
adapt the notion of class final methods to interfaces.

This is not easy to do, since it is a language change,
and only applies to a small (though influential) number of
methods, those which should *not* be overridable but
*should* (for some reason of API design) support virtual
(fluent, postfix, left-to-right) notation.

For more details please see JDK-8191530 and if you
think of a good use case for these thingies, let me know
so I can add it to the write-up.

— John


More information about the core-libs-dev mailing list