This discussion is archived
1 2 Previous Next 15 Replies Latest reply: Mar 25, 2011 4:31 PM by jschellSomeoneStoleMyAlias RSS

suggestion: immutable collection interfaces

847718 Newbie
Currently Being Moderated
Would it be possible to extend the Java Collections API with immutable versions of interfaces?
E.g. add an ImmutableCollection interface which Collection extends. All the get() methods would go into ImmutableCollection, and all the modification methods
would go into Collection. Likewise for ImmutableList/List, etc. Also, ImmutableIterator would have the hasNext() and next() methods, while Iterator would
extend it and add the remove() method.
This wouldn't break any existing code, but would allow new code to formally identify read-only views. E.g. many methods return a read-only view of a collection;
they could return an ImmutableList instead of a list. Then attempts to change the list would be caught at compile-time, not run-time.

Would there be any downsides to such a change?

Thanks,

ilya
  • 1. Re: suggestion: immutable collection interfaces
    EJP Guru
    Currently Being Moderated
    See the Collections Framework Overview. Your suggestion was considered first thing in about 1997 and rejected for the reasons stated therein.

    If code needs to know at runtime whether a given collection is mutable/immutable there is something seriously wrong elsewhere.
  • 2. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    Thanks for the link. The goal of having few core interfaces makes sense.
    If code needs to know at runtime whether a given collection is mutable/immutable there is something seriously wrong elsewhere.
    Sorry, didn't understand this -- could you please explain?
    I thought we were talking about providing more information at compile time?

    One other point:
    In 1997, covariant return-type overriding didn't exist. Now that it does, you could have Collection extend ImmutableCollection, Iterator extend ImmutableIterator,
    and Collection.iterator() return an Iterator even though ImmutableCollection.iterator() returns an ImmutableIterator.
    In 1997, Collection would have had to return ImmutableIterator, losing much of the benefit of the separation.

    Also, today there are much better static analysis tools than in 1997. Knowing immutability at compile-time would be very useful for checking correctness.
    Concurrency is also used much more today, and immutability helps reason about concurrency.

    Are there other considerations against this, in addition to the increased number of classes?

    Thanks,

    ilya

    Edited by: 844715 on Mar 16, 2011 8:20 PM
  • 3. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    Thanks for the link. The goal of having few core interfaces makes sense.
    If code needs to know at runtime whether a given collection is mutable/immutable there is something seriously wrong elsewhere.
    Sorry, didn't understand this -- could you please explain?
    I thought we were talking about providing more information at compile time?

    One other point:
    In 1997, covariant return-type overriding didn't exist. Now that it does, you could have Collection extend ImmutableCollection, Iterator extend ImmutableIterator,
    Bad idea.
    ImmutableCollection coll = new MutableArrayList();
    Oh, look, coll is immutable, so I can pass it around and not worry about it being modified under me. (Dun dun DAAHHHH!!!)
  • 4. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    ImmutableCollection coll = new MutableArrayList();
    Oh, look, coll is immutable, so I can pass it around and not worry about it being modified under me. (Dun dun DAAHHHH!!!)
    If you pass it to a method that takes an ImmutableCollection, that method would have to explicitly cast it to Collection before modifying it, right?
    With generics, casts are rare, so this would stand out in the code.
    It's just like the 'const *' qualifier in C/C++ -- it can be overridden by explicit casting, but people use it all the time anyway, because casts are rare.
    Catching some bugs at compile time is still useful even if you can't catch all.
  • 5. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    ImmutableCollection coll = new MutableArrayList();
    Oh, look, coll is immutable, so I can pass it around and not worry about it being modified under me. (Dun dun DAAHHHH!!!)
    If you pass it to a method that takes an ImmutableCollection, that method would have to explicitly cast it to Collection before modifying it, right?
    True, but irrelevant. The method can modify it, unbeknown to me. And that's just one example. I wrote the simplest code I could to demonstrate. The point is that something that IS-A ImmutableCollection actually does not meet the documented (but in this model, unenforceable) contract.
    With generics, casts are rare
    I wouldn't say rare. Just no longer omnipresent.
    , so this would stand out in the code.
    Doesn't matter. I think I have an ImmutableCollection, because that's what the variable is declared as. I don't know what the actual type is, but I'm assuming that because it IS-A Immutable that it lives up to Immutable's contract. It doesn't.
    Catching some bugs at compile time is still useful even if you can't catch all.
    Declaring something Immutable when it quite easily can be otherwise is just bad design.
  • 6. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    Declaring something Immutable when it quite easily can be otherwise is just bad design.
    You're not declaring that the object is immutable: you're declaring that you will not modify it through this particular reference.
    Likewise, when a method says it takes an ImmutableCollection argument, it formally promises that it will not modify the collection.
    If 99% of methods that make this promise obey it (as is the case in C/C++), this promise is useful information for reasoning about program correctness.
    It is also easy for an automatic tool to find & flag all explicit casts from an immutable to a mutable object.

    When you write "List<T> a = new ArrayList<T>", you declare that when working with 'a' you only need the operations of List, not any additional operations of ArrayList.
    This simplifies reasoning about your code. Similarly, when you say that a certain reference only has a read-only view of an object, this helps reason about the
    code, as you don't have to worry about that reference when looking for ways that your object could be modified.
  • 7. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    Declaring something Immutable when it quite easily can be otherwise is just bad design.
    You're not declaring that the object is immutable: you're declaring that you will not modify it through this particular reference
    I couldn't disagree more. I'll opt out at this point, now that I understand where you're coming from. (Still disagree though. :-) )

    EDIT:
    I will note that I have used that type hierarchy occasionally (including quite recently), but I declare the parent as X and the child as MutableX. Same functionality, but the distinction is that I don't promise immutability at the parent level, but rather, but using the "may-or-may-not-be-mutable" parent, I'm saying I don't need mutability.

    What you're saying sounds similar, but I have a serious problem with calling something Immutable when it's not guaranteed to be immutable, so maybe it's just a matter of naming convention.

    If that's the case, however, and we then go back and reexamine the discussion from the point of MutableCollection extends Collection, I don't know whether I think that'd be a good idea, and I'm not presently interested enough to pursue that line of though.

    Edited by: jverd on Mar 17, 2011 1:49 PM
  • 8. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    declare the parent as X and the child as MutableX. Same functionality, but the distinction is that I don't promise immutability at the parent level, but rather, but using the "may-or-may-not-be-mutable" parent, I'm saying I don't need mutability.
    I agree, that's better -- I've been doing the same thing recently. (Though, not because of "may be mutable" concerns, but because immutable vars are much more common & making that the default saves on typing :) ).
    Unfortunately, when retrofitting an existing hierarchy, this wouldn't be an option: "List" is by now entrenched to mean "MutableList".

    Instead of ImmutableCollection, a better name would be CollectionViewReadOnly -- making clear that it's only a read-only view of a collection, and making no statement about the collection itself.
    In general, an interface always declares what an object can do -- never what it can't -- but you're right that ImmutableCollection can be read as describing what the referenced object can't do.

    Ok, thanks for the discussion!

    ilya

    Edited by: 844715 on Mar 17, 2011 6:25 PM
  • 9. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    In general, an interface always declares what an object can do -- never what it can't -- but you're right that ImmutableCollection can be read as describing what the referenced object can't do.
    I prefer to think of it as promising that it can (and does) protect its own state from changing. :-)
  • 10. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    I prefer to think of it as promising that it can (and does) protect its own state from changing
    Would be nice, but since an interface can never prevent mutable classes from implementing it, it can never do that.
    So, you're right, an interface named ImmutableCollection would be confusing.
    What I really wanted was an interface named CollectionViewReadOnly.
    Would that still be problematic?
  • 11. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    I prefer to think of it as promising that it can (and does) protect its own state from changing
    Would be nice, but since an interface can never prevent mutable classes from implementing it, it can never do that.
    Which is why we don't declare it as Immutable, which would imply that it is promising immutability.
    So, you're right, an interface named ImmutableCollection would be confusing.
    What I really wanted was an interface named CollectionViewReadOnly.
    Would that still be problematic?
    An interface named Immutable or ReadOnly isn't a problem in and of itself. The problem comes (IMHO) when a mutable class implements that interface (or extends an Immutable or ReadOnly class). It's like declaring something Comparable, and then having its compareTo() method simply always return 1.

    Personally, I'd like an immutable keyword that could be applied to any class or perhaps any object. (I haven't really thought through yet which makes more sense, but I'm leaning toward class.) You declare a class immutable, and the compiler enforces it by, for example, making sure that every member variable is final, and if it's a reference type, is itself immutable. I don't know whether it makes sense to allow a mutable class to extends an immutable one, but that's a different issue that this one, because it's not (or may not be) an IS-A relationship. The key point being compile-time enforcement of immutability.

    Edited by: jverd on Mar 18, 2011 3:09 AM
  • 12. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    The problem comes (IMHO) when a mutable class implements that interface (or extends an Immutable or ReadOnly class).
    Right, but I think an interface named "ReadOnlyViewOfCollection" cures that problem. A mutable collection can export a read-only
    view of itself, for use by code that only needs to read the collection. Implementing such an interface does not imply that the collection
    is read-only: only that, when accessed through this view, the compiler will catch any inadvertent modifications.
    I'd like an immutable keyword that could be applied to any class or perhaps any object
    That would be useful as well.
    But letting mutable objects expose read-only views of themselves would be a separately useful thing:
    then the set of execution paths along which the object could mutate would be greatly reduced,
    which helps reason about correctness. It's similar to using private/protected etc modifiers to limit
    access to class members: a member is accessible, but only but a subset of the program; an object
    is modifiable, but only by a subset of the program.
  • 13. Re: suggestion: immutable collection interfaces
    796440 Guru
    Currently Being Moderated
    844715 wrote:
    The problem comes (IMHO) when a mutable class implements that interface (or extends an Immutable or ReadOnly class).
    Right, but I think an interface named "ReadOnlyViewOfCollection" cures that problem. A mutable collection can export a read-only
    view of itself, for use by code that only needs to read the collection. Implementing such an interface does not imply that the collection
    is read-only: only that, when accessed through this view, the compiler will catch any inadvertent modifications.
    That sounds like C++ experience leaking through. For me, "ReadOnlyView" means that it cannot be modified, not just that the one declaring a variable as won't modify it. To me implementing a ReadOnly interface does imply that the collection cannot be modified. That is an interesting take on it though. I think I'll keep that in the back of my mind.

    Note that the Collections.unmodifiableXxx() return true read-only views (as in, you cannot modify the collection through them). Of course, one still has to be careful where one lets the modifiable version escape to. And there's no type hierarchy with an "Immutable" portion in the type name.
    But letting mutable objects expose read-only views of themselves would be a separately useful thing:
    then the set of execution paths along which the object could mutate would be greatly reduced,
    which helps reason about correctness.
    You get that to some degree with the Collections.unmodifiableXxx(). Now if Immutable or Unmodifiable or whatever were the subtype, and all the mutation methods were final and threw UnsupportedOperationException, then I might feel more comfortable with it. (Though I haven't really given much though to the implications of that kind of hierarchy.) My main problem with Immutable as you've described it so far is, as I've mentioned, that I don't want to have a mutable subtype of an immutable type, especially if the parent is named "Immutable." That seems like it would put a serious dent in the usefulness of that type in reasoning out correctness.
  • 14. Re: suggestion: immutable collection interfaces
    847718 Newbie
    Currently Being Moderated
    That sounds like C++ experience leaking through.
    Well, yes :) Not to defend everything about C++ (there's a reason I'm reading Java forums :) ), but the common practice of specifying mutability
    is (in my experience) a good thing.
    For me, "ReadOnlyView" means that it cannot be modified, not just that the one declaring a variable as won't modify it. To me implementing a ReadOnly interface does imply that the collection cannot be modified. That is an interesting take on it though. I think I'll keep that in the back of my mind.
    And I'll keep your take -- it hasn't occurred to me either :)
    Collections.unmodifiableXxx() return true read-only views
    Yes, of course, and I use it whenever I can. But it's a dynamic construct: the compiler can't check that you use it. Say you write a method that takes someone's List, and you want to ensure that you don't modify it. You could wrap the list in an unmodifiable wrapper and only save that
    reference. But the compiler can't check that that's the only way you access the list.
    On the other hand, if you declare your method as taking a ReadOnlyView of someone's list, the compiler won't let you modify their list, and this restriction appears in the API (not just in the comments).
    While in theory you could downcast it to a modifiable list, in practice you practically never will -- certainly not unintentionally. So a read-only view of someone's possibly modifiable structures is a common idiom, and it would be good if there was a formal
    way to express it, as there is in C/C++.

    I just feel much safer writing code that takes someone's (possibly mutable) structure, when I know that I can't change it by accident.
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points