<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<p><br>
</p>
<div class="moz-cite-prefix">On 24/08/2022 15:38, Ethan McCue wrote:<br>
</div>
<blockquote type="cite"
cite="mid:CA+NR86jJrzNdpVPNVkOrApZ8uw3EorPC5WL-Gz=SkgbwzH2ZDA@mail.gmail.com">
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<div dir="auto">A use case that doesn't cover is adding to a
collection.</div>
</blockquote>
<blockquote type="cite"
cite="mid:CA+NR86jJrzNdpVPNVkOrApZ8uw3EorPC5WL-Gz=SkgbwzH2ZDA@mail.gmail.com">
<div dir="auto">
<div dir="auto">Say as part of a method's contract you state
that you take ownership of a List. You aren't going to copy
even if the list is mutable.</div>
<div dir="auto"><br>
</div>
<div dir="auto">Later on, you may want to add to the list. Add
is supported on ArrayList so you don't need to copy and
replace your reference, but you would if the list you were
given was made with List.of or Arrays.asList</div>
</div>
</blockquote>
<p>I don't think this is a common enough use case that should be
catered for. It might be better handled with concurrent lists
instead.</p>
<p>The most common use case by far is wanting to make sure a
collection you've received is not going to be modified while you
are working with it. I don't think another proposal which does
cover the most common cases should be dismissed out of hand
because it doesn't support a rather rare use case.<br>
</p>
--John<br>
<p><br>
</p>
<blockquote type="cite"
cite="mid:CA+NR86jJrzNdpVPNVkOrApZ8uw3EorPC5WL-Gz=SkgbwzH2ZDA@mail.gmail.com"><br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Wed, Aug 24, 2022, 8:13 AM
John Hendrikx <<a href="mailto:john.hendrikx@gmail.com"
moz-do-not-send="true" class="moz-txt-link-freetext">john.hendrikx@gmail.com</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>
<p>Would it be an option to not make the receiver
responsible for the decision whether to make a copy or
not? Instead put this burden (using default methods) on
the various collections?</p>
<p>If List/Set/Map had a method like this:</p>
<p> List<T> immutableCopy(); // returns a
(shallow) immutable copy if list is mutable (basically
always copies, unless proven otherwise)</p>
<p>Paired with methods on Collections to prevent collections
from being modified:</p>
<p> Collections.immutableList(List<T>)</p>
<p>This wrapper is similar to `unmodifiableList` except it
implements `immutableCopy` as `return this`.<br>
</p>
<p>Then for the various scenario's, where `x` is an
untrusted source of List with unknown status:<br>
</p>
<p> // Create a defensive copy; result is a private list
that cannot be modified:<br>
</p>
<p> List<T> y = x.immutableCopy(); <br>
</p>
<p> // Create a defensive copy for sharing, promising it
won't ever change:<br>
</p>
<p> List<T> y =
Collections.immutableList(x.immutableCopy()); <br>
</p>
<p> // Create a defensive copy for mutating:</p>
<p> List<T> y = new ArrayList<>(x); // same
as always</p>
<p> // Create a mutable copy, modify it, then expose as
immutable:</p>
<p> List<T> y = new ArrayList<>(x); // same
as always</p>
<p> y.add( <some element> ); <br>
</p>
<p> List<T> z = Collections.immutableList(y);</p>
<p> y = null; // we promise `z` won't change again by
clearing the only path to mutating it!<br>
</p>
<p>The advantage would be that this information isn't part
of the type system where it can easily get lost. The
actual implementation knows best whether a copy must be
made or not.</p>
<p>Of course, the immutableList wrapper can be used
incorrectly and the promise here can be broken by keeping
a reference to the original (mutable) list, but I think
that's an acceptable trade-off.</p>
<p>--John</p>
<p>PS. Chosen names are just for illustration; there is some
discussion as what "unmodifiable" vs "immutable" means in
the context of collections that may contain elements that
are mutable. In this post, immutable refers to shallow
immutability .</p>
<div>On 24/08/2022 03:24, Ethan McCue wrote:<br>
</div>
<blockquote type="cite">
<div dir="auto">Ah, I'm an idiot.
<div dir="auto"><br>
</div>
<div dir="auto">There is still a proposal here
somewhere...maybe. right now non jdk lists can't
participate in the special casing?</div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Tue, Aug 23, 2022,
9:00 PM Paul Sandoz <<a
href="mailto:paul.sandoz@oracle.com" target="_blank"
rel="noreferrer" moz-do-not-send="true"
class="moz-txt-link-freetext">paul.sandoz@oracle.com</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0 0 0
.8ex;border-left:1px #ccc solid;padding-left:1ex">List.copyOf
already does what you want.<br>
<br>
<a
href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/List.java#L1068"
rel="noreferrer noreferrer noreferrer"
target="_blank" moz-do-not-send="true"
class="moz-txt-link-freetext">https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/List.java#L1068</a><br>
<a
href="https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/ImmutableCollections.java#L168"
rel="noreferrer noreferrer noreferrer"
target="_blank" moz-do-not-send="true"
class="moz-txt-link-freetext">https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/java/util/ImmutableCollections.java#L168</a><br>
<br>
Paul.<br>
<br>
> On Aug 23, 2022, at 4:49 PM, Ethan McCue <<a
href="mailto:ethan@mccue.dev" rel="noreferrer
noreferrer" target="_blank" moz-do-not-send="true"
class="moz-txt-link-freetext">ethan@mccue.dev</a>>
wrote:<br>
> <br>
> Hi all,<br>
> <br>
> I am running into an issue with the collections
framework where I have to choose between good
semantics for users and performance.<br>
> <br>
> Specifically I am taking a java.util.List from my
users and I need to choose to either<br>
> * Not defensively copy and expose a potential
footgun when I pass that List to another thread<br>
> * Defensively copy and make my users pay an
unnecessary runtime cost.<br>
> <br>
> What I would really want, in a nutshell, is for
List.copyOf to be a no-op when used on lists made with
List.of().<br>
> <br>
> Below the line is a pitch I wrote up on reddit 7
months ago for a mechanism I think could accomplish
that. My goal is to share the idea a bit more widely
and to this specific audience to get feedback.<br>
> <br>
> <a
href="https://www.reddit.com/r/java/comments/sf8qrv/comment/hv8or92/?utm_source=share&utm_medium=web2x&context=3"
rel="noreferrer noreferrer noreferrer"
target="_blank" moz-do-not-send="true">https://www.reddit.com/r/java/comments/sf8qrv/comment/hv8or92/?utm_source=share&utm_medium=web2x&context=3</a>
<br>
> <br>
> Important also for context is Ron Pressler's
comment above.<br>
> --------------<br>
> <br>
> What if the collections api added more marker
interfaces like RandomAccess?<br>
> <br>
> It's already a common thing for codebases to make
explicit null checks at error boundaries because the
type system can't encode null | List<String>. <br>
> <br>
> This feels like a similar problem.<br>
> If you have a List<T> in the type system
then you don't know for sure you can call any methods
on it until you check that its not null. In the same
way, there is a set of methods that you don't know at
the type/interface level if you are allowed to call.<br>
> <br>
> If the List is actually a __<br>
> Then you can definitely call<br>
> And you know other reference holders might call<br>
> And you can confirm its this case by<br>
> null<br>
> no methods<br>
> no methods<br>
> list == null<br>
> List.of(...)<br>
> get, size<br>
> get, size<br>
> ???<br>
> Collections.unmodifiableList(...)<br>
> get, size<br>
> get, size, add, set<br>
> ???<br>
> Arrays.asList(...)<br>
> get, size, set<br>
> get, size, set<br>
> ???<br>
> new ArrayList<>()<br>
> get, size, add, set<br>
> get, size, add, set<br>
> ???<br>
> While yes, there is no feasible way to encode
these things in the type system. Its not impossible to
encode it at runtime though.<br>
> interface FullyImmutable {<br>
> // So you know the existence of this implies the
absence<br>
> // of the others<br>
> default Void cantIntersect() { return null; }<br>
> }<br>
> <br>
> interace MutationCapability {<br>
> default String cantIntersect() { return ""; }<br>
> }<br>
> <br>
> interface Addable extends MutationCapability {}<br>
> interface Settable extends MutationCapability {}<br>
> <br>
> If the List is actually a __<br>
> Then you can definitely call<br>
> And you know other reference holders might call<br>
> And you can confirm its this case by<br>
> null<br>
> no methods<br>
> no methods<br>
> list == null<br>
> List.of(...)<br>
> get, size<br>
> get, size<br>
> instanceof FullyImmutable<br>
> Collections.unmodifiableList(...)<br>
> get, size<br>
> get, size, add, set<br>
> !(instanceof Addable) && !(instanceof
Settable)<br>
> Arrays.asList(...)<br>
> get, size, set<br>
> get, size, set<br>
> instanceof Settable<br>
> new ArrayList<>()<br>
> get, size, add, set<br>
> get, size, add, set<br>
> instanceof Settable && instanceof Addable<br>
> In the same way a RandomAccess check let's
implementations decide whether they want to try an
alternative algorithm or crash, some marker
"capability" interfaces would let users of a
collection decide if they want to clone what they are
given before working on it.<br>
> <br>
> <br>
> --------------<br>
> <br>
> So the applicability of this would be that the
list returned by List.of could implement
FullyImmutable, signifying that there is no caller
which might have a mutable handle on the collection.
Then List.of could check for this interface and skip a
copy.<br>
> <br>
> <br>
<br>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</div>
</blockquote>
</body>
</html>