I was running into problems with different teams at my employer using different Immutable Collection implementations and wanted to avoid writing code to adapt each Collection

Larry Diamond ldiamond at ldiamond.com
Tue Feb 2 01:44:05 UTC 2021


Thank you for taking the time to look over my proposal and give it some
really good thought.

I really like the idea of calling the interfaces "Readable" rather than
"Unmodifiable".
I agree that the every ArrayList is "Immutable" since that clearly isn't my
intent here,
and I like the "Readable" term much better than "Immutable" or
"Unmodifiable" and you've
clearly internalized what I was thinking about and are very familiar with
the Guava and Eclipse
attempts to implement this concept.  (and of yeah Readable is a lot easier
to spell than Unmodifiable!)

There are definitely some methods on the existing interfaces that would
need to change
types to accept ReadableCollection rather than Collection.   I'll compile a
list so at least
everybody can take a look at how big of a change that would be.

The for-loop connection to Iterable would need to change to
ReadableIterable.
I'm not sure how big of a job that is to change that, but since Iterable
would extend ReadableIterable
no existing code should be broken by that change.

My original idea was that Immutability is a "view" of the underlying
Collection and so changes
to the underlying Collection would change the Immutable view.
My original goal is to prevent software defects by allowing "readers" of a
Collection to have different rights
to that Collection than "owners" - to pass in an Immutable view of a
Collection into a method and be confident
that method could not change the Collection, and for the readers of that
Collection to be aware of that at compile
time and not run time.

   public void myMethod (Set<Something> mySet) {
      ReadableSet <Something> myReadableSet = mySet;
      boolean whatever = someOtherMethod (myReadableSet);

I know that someOtherMethod will never modify mySet and a developer
attempting
to do so will be blocked by the compiler.   It certainly does not prevent
another thread from
modifying mySet, just like today with a ConcurrentSkipListSet.   The
difference is that the developer
is preventing from compiling code that damages mySet, preventing the
introduction of unexpected behavior
from future code after the original developers have moved onto other
projects.

My original intent was to have an "unmodifiable view" rather than a
"shallowly immutable" Collection.
If somebody wants to have a "shallowly immutable" Collection, that can make
a "unmodifiable view" of
what they want in their Collection and then throw away the original
Collection reference and only use the
"unmodifiable view" in their code.

   Set<Something> mySet = loadFromDatabase();
   ReadableSet<Something> myReadableSet = mySet;
   mySet = null;

As regards to the List.of() methods and similar methods, I've proposed
List.uof() (Unmodifiable Of,
perhaps now rof() to say ReadableOf methods in the Readable interfaces that
would have default
implementations in the existing interfaces to return the value of the
existing of() method.
ReadableList<String> myList = ReadableList.rof ("A", "B", "C");
would be the same as
ReadableList<String> myList = List.of ("A", "B", "C");
and I hope that the default implementations in List reduce the need for
any implementing class
from needing to change - that is a goal of this design.

I agree that when the Collections framework was first created that these
classes wouldn't have made sense.
With (at least) three well known high quality attempts at hitting this
target, there's clearly some different
opinions in the community.   I think the use cases for Java applications
are much different now than they were
when the framework was written, many of them thanks to the success of
Java.  One of the documents that has
been referred to is
https://docs.oracle.com/javase/8/docs/technotes/guides/collections/designfaq.html#a2
which
states that in the case of a programming error that the program should
halt.   In the command line use cases
when the framework was written, I think that was a very reasonable decision
and reasonable behavior, and
now we've all no doubt had more than a few conversations about defensive
programming - I think the newer
use cases warrant a reconsideration of what I think was the right decision
at the time.   Software defects are
much more common now and I can't think of a single very large application
that does not have some defects
in them somewhere, even if we don't see them very often.   Security related
defects are particularly troublesome
and were not so much of an issue before we all had publicly accessible
RESTFul endpoints in our applications.

Thank you both very much for taking the time to discuss my suggestion in
extremely intelligent depth.
I greatly appreciate your feedback and consideration.

I will review the interfaces and come up with a list of methods where the
signature might change to accept
"Readable" interfaces.

Thank you very much
Larry Diamond









On Mon, Feb 1, 2021 at 7:17 PM Stuart Marks <stuart.marks at oracle.com> wrote:

> As Remi pointed out, retrofitting the interfaces this way would imply that
> ArrayList
> implements UnmodifiableCollection. (This seems semantically wrong in the
> first
> place, but it might be mitigated by renaming things to ReadableCollection
> etc.)
>
> Another point is that UnmodifiableCollection isn't a Collection, so adding
> its
> elements to an existing collection via myArrayList.addAll(unmodcoll) would
> no longer
> work without some additional adaptation.
>
> Additionally, UnmodifiableCollection would implement UnmodifiableIterable
> but not
> Iterable, so it would no longer be possible to iterate using a for-loop.
> Again, not
> without additional adaptation.
>
> I've written some about this issue here:
>
>      https://stackoverflow.com/a/57926310/1441122
>
> One alternative this SO answer doesn't cover is having no type
> relationship between
> UnmodifiableCollection and Collection, similar to the way Eclipse
> Collections does
> it. That's another stable point in the design space, and it has a bunch of
> different
> tradeoffs. It also requires the addition of a bunch of adapters between
> the hierarchies.
>
> A central decision is whether "unmodifiable" allows unmodifiability to be
> cast away,
> whether it permits modification only via another reference (an
> "unmodifiable view"),
> or whether it indicates the underlying collection itself is unmodifiable
> ("shallowly
> immutable"). Closely related is the issue of what to do about the return
> type of
> methods like List.of() and Collections.unmodifiableList() and related
> methods.
>
> Remi noted previously that the idea of unmodifiable collection interfaces
> was
> rejected from the initial design. That doesn't mean it's a bad idea and
> that they
> can never be added. Indeed, proposals and questions in this area do come
> up from
> time to time. The problem is that doing this (for whatever definition of
> "this") is
> harder than it seems at first glance, and the benefits provided have never
> been
> quite able to justify the additional complexity this would add to the
> platform.
>
> s'marks
>
>
>
> On 1/31/21 2:10 PM, Larry Diamond wrote:
> > Wow thanks for getting back to me so quickly.   I'll read over the
> existing
> > conversation.   Thank you very much
> >
> > On Sun, Jan 31, 2021 at 4:19 PM Remi Forax <forax at univ-mlv.fr> wrote:
> >
> >> Hi Larry,
> >> this design was considered and rejected when the collection API vas
> >> introduced in JDK 1.2
> >> see
> >>
> https://mail.openjdk.java.net/pipermail/core-libs-dev/2020-May/066245.html
> >>
> >> Furthermore, if List extends ImmutableList, it means that ArrayList
> >> implements ImmutableList which is just plain wrong.
> >> Consider the following code
> >>    record Foo(ImmutableList<String> list) { }
> >>    var arrayList = new ArrayList<String>();
> >>    var foo = new Foo(arrayList);
> >>    System.out.println(foo.list()); // []
> >>    arrayList.add("oops");
> >>    System.out.println(foo.list()); // [oops]
> >>
> >> regards,
> >> Rémi
> >>
> >> ----- Mail original -----
> >>> De: "Larry Diamond" <ldiamond at ldiamond.com>
> >>> À: "jdk-dev" <jdk-dev at openjdk.java.net>
> >>> Envoyé: Dimanche 31 Janvier 2021 21:28:33
> >>> Objet: I was running into problems with different teams at my employer
> >> using different Immutable Collection
> >>> implementations and wanted to avoid writing code to adapt each
> Collection
> >>
> >>> I was thinking of submitting a proposal for UnmodifiableCollections for
> >>> Java.
> >>>
> >>> I wrote up a first draft of a JEP for this.
> >>>
> >>> What do you think?
> >>>
> >>> Thank you very much
> >>> Larry Diamond
> >>
>


More information about the jdk-dev mailing list