<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>