Timeline for Why doesn't Java 8 include immutable collections?
Current License: CC BY-SA 3.0
26 events
when toggle format | what | by | license | comment | |
---|---|---|---|---|---|
Dec 21, 2022 at 16:25 | comment | added | supercat | @bdsl: Treating external resources as immutable collections is often useful, and in many cases it may be tolerable to design things so that a resource that goes off line will trigger a cascade of exceptions that inelegantly terminates a program, but in some cases, especially with interactive programs, it may be more useful to have a program announce "Resource unavailable" to the user and then skip any operations which relied upon its contents, but allow actions that don't depend upon the contents to proceed anyway. | |
Dec 21, 2022 at 16:18 | comment | added | supercat | @bdsl: There may also be situations where an "add-only" collection interface might be usable in much the same was as an immutable interface, if it specifies that any item which is ever observed to exist will never change, but changes to the original may or may not be reflected in snapshots thereof. This should be a parent interface of one that guarantees such extensions won't happen, since some kinds of wrappers would uphold a stronger immutability guarantee if the wrapped objects do, but would fail to uphold a weaker guarantee if wrapped objects only uphold that. | |
Dec 21, 2022 at 16:07 | comment | added | bdsl | The interface that reads from a CD on demand shouldn't be thought of as like an immutable data structure held inside the programs memory. It's an I/O mechanism, not a collection - unless you want to say the computer should be treated as out-of-order and not to be used any time the CD is taken out. | |
Dec 21, 2022 at 16:04 | comment | added | bdsl | @supercat I think your terminology is very clear. I just wanted to let people know that they can find many other people agreeing with you, and going into more detail on the general principles involved, by searching for "liskov history constraint". | |
Dec 21, 2022 at 16:03 | comment | added | supercat | ...imply that the implementation was broken, if the possibility of the resource being unavailable had been accounted for in the interface. If code asks for item #5 of an item held on a CD-ROM, and then asks for that item at a later time while the CD is being taken out for periodic cleaning, an implementation that returns item #5 would be correct, but so would one that reports "resource temporarily unavailable", even though the latter response doesn't match the first. | |
Dec 21, 2022 at 16:00 | comment | added | supercat | @bdsl: I'm not familiar enough with the terminology to know the phrase "history constraint". Are you suggesting Liskov's terminology would be clearer than "Any implementation of an immutable interface which does not always return the same data in response to a particular request is broken"? I suppose there are some corner cases where the meanings could be slightly different if an interface has a means of reporting "resource unavailable"; the fact that one attempt to read data from an immutable interface succeeds and another reports "resource unavailable" would not necessarily... | |
Dec 21, 2022 at 15:10 | comment | added | bdsl | Very good answer. It might be worth adding that a mutable collection derived from an immutable collection would be a violation of the Liskov Substitution Principle's history constraint. | |
Aug 23, 2017 at 23:03 | comment | added | supercat | ...permanent condition), could automatically implement methods for cloning and for equality/equivalence testing in most cases. Treating all references the same way may simplify the language, but makes it necessary to manually write a lot of code that would otherwise not be necessary. | |
Aug 23, 2017 at 23:02 | comment | added | supercat | @maaartinus: A more general problem with Java is that it fails to distinguish between references that exist to encapsulate state stored in private mutable objects, those that exist to encapsulate state stored in objects that will never be mutated (whether or not they are of mutable type), references that "own" mutable objects to which other entities also have access, and references that identify mutable objects owned by other entities. A language that distinguished those kinds of references, and has separate methods for equality and equivalence (the latter being a stronger and... | |
Aug 23, 2017 at 22:57 | comment | added | BeeOnRope | @maaartinus - I agree. There are upsides and downsides and early Java erred on the side of less complexity in general and also perhaps the usefulness of immutable collections wasn't as apparent 20 years ago. | |
Aug 23, 2017 at 22:55 | comment | added | maaartinus | @BeeOnRope It only explains, why the proposed hierarchy is wrong. But with a slight modification reflecting this answer, it could work. I'm still missing why no attempt were done, especially when there are so many open source immutable collections in widespread use (mainly Guava). | |
Feb 20, 2016 at 3:17 | comment | added | BeeOnRope | This should be the accepted answer, as it answers explicitly why the provided hierarchy cannot work based on basic object-oriented principles. | |
Aug 12, 2015 at 6:39 | comment | added | Patrick M | @LaurentBourgault-Roy In general, you have to assume people aren't doing evil things using reflection. If they are, you're already screwed, since you can't even trust that numbers will behave sanely: codegolf.stackexchange.com/a/28818/7786 . Either trust that they won't, or change languages. | |
Dec 6, 2014 at 17:02 | comment | added | supercat | @LaurentBourgault-Roy: No mechanism via which the method creating the object can force the generated machine code to do the necessary work there, without imposing extra obligations on the part of any code reading it. | |
Dec 6, 2014 at 17:01 | comment | added | supercat | @LaurentBourgault-Roy: Since the cases where lazy content generation is most appropriate are those where many things will either be read zero times or thousands, it's often good to focus on minimizing the cost of reading already-generated data. Unfortunately, the way the JLS is written, such an objective would be inconsistent with a desire to make all immutable classes inherently thread-safe. From a hardware perspective, on every platform I've read of or can imagine, the creator of the data would have to do extra work to ensure safety but the reader would not. Unfortunately, Java provides... | |
Dec 6, 2014 at 16:41 | comment | added | supercat | @LaurentBourgault-Roy: Since writing the above, I've come to realize a rather annoying "feature" of Java's memory model which distinguishes between immutable and effectively-immutable fields: if an immutable type uses a backing store of a mutable type to hold lazily-generated content, making it thread-safe will require extra work not only on the part of code generating the content (not a problem, since such code would only execute once, and the the extra work will likely be cheap relative to the cost of generating the content) but will also require extra work whenever the content is read. | |
Dec 23, 2013 at 16:51 | comment | added | supercat | let us continue this discussion in chat | |
Dec 23, 2013 at 16:51 | comment | added | supercat |
@LaurentBourgault-Roy: The fundamental question is whether one trusts people not to produce broken implementations or derived classes. If one does, and if the interfaces/base classes provide asMutable/asImmutable methods, it may be possible to improve performance by many orders of magnitude [e.g. compare the cost of calling asImmutable on an instance of the above-defined sequence versus the cost of constructing an immutable array-backed copy]. I would posit that having interfaces defined for such purposes is probably better than trying to use ad-hoc approaches; IMHO, the biggest reason...
|
|
Dec 23, 2013 at 16:43 | comment | added | Laurent Bourgault-Roy | I fully agree. My solution give you correctness (up to a point), but to get performance with large dataset, you must have persistent structure and design for immutability from the beginning. For small collection though you can get away with taking an immutable copy from time to time. I remember that Scala did some analysis of various program and found that something like 90% of the lists instanciated were 10 or less items long. | |
Dec 23, 2013 at 16:39 | comment | added | supercat |
@LaurentBourgault-Roy: Given a ReadableIndexedIntSequence , one could produce an instance of an array-backed immutable type by copying all the items into an array, but suppose that a particular implementation simply returned 16777216 for length and ((long)index*index)>>24 for each item. That would be a legitimate immutable sequence of integers, but copying it to an array would be a huge waste of time and memory.
|
|
Dec 23, 2013 at 16:39 | comment | added | Laurent Bourgault-Roy | Indeed. No silver bullet here. And even a sealed class can be defeated using reflection. | |
Dec 23, 2013 at 16:34 | comment | added | supercat |
@LaurentBourgault-Roy: There are advantages to both sealed and inheritable immutable types. If one doesn't want to allow an illegitimate derived class to break one's invariants, sealed types can offer protection against that while inheritable classes offer none. On the other hand, it may be possible for code that knows something about the data it holds to store it much more compactly than would a type that knows nothing about it. Consider, for example, a ReadableIndexedIntSequence type which encapsulates a sequence of int , with methods getLength() and getItemAt(int) .
|
|
Dec 23, 2013 at 15:12 | comment | added | Laurent Bourgault-Roy | Great answer. Immutable collections can give you a pretty strong guarantee related to thread-safeness and how you can reason about them as time goes by. A Readable/Read-only collection does not. In fact, to honor the liskov substition principle, Read-Only and Immutable should probably be abstract base type with final method and private members to ensure that no derived class can destroy the garantee given by the type. Or they should be fully concrete type that either wrap a collection (Read-Only), or always take a defensive copy (Immutable). This is how guava ImmutableList does it. | |
S Dec 23, 2013 at 15:01 | history | suggested | Bart van Heukelom | CC BY-SA 3.0 |
fixed small mistakes that reverse the intended meaning
|
Dec 23, 2013 at 14:55 | review | Suggested edits | |||
S Dec 23, 2013 at 15:01 | |||||
Dec 21, 2013 at 8:37 | history | answered | supercat | CC BY-SA 3.0 |