<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body>
    <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 class="moz-cite-prefix">On 24/08/2022 03:24, Ethan McCue wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CA+NR86jY8irHa+CxUgLAGH12=vmL3kBY4xzcNkqFjN+n5gbVTw@mail.gmail.com">
      <meta http-equiv="content-type" content="text/html; charset=UTF-8">
      <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"
            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" 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" 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" target="_blank"
            rel="noreferrer" 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" 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>
  </body>
</html>