Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preferring mutable or immutable collections as method parameters

I'm writing a library method that will be used in several places. One of the method's parameters is a collection of objects, and the method does not mutate this collection. Should the method signature specify a mutable or immutable collection?

Option 1: mutable collection as parameter

public static void foo(List<Bar> list) {
  // ...
}

Pros: Clients can pass in whichever of List<Bar> or ImmutableList<Bar> is more convenient for them.

Cons: It is not immediately obvious that the list parameter will not be mutated. Clients must read documentation and/or code to realize this. Clients may make unnecessary defensive copies anyway.

Option 2: immutable collection as parameter

public static void foo(ImmutableList<Bar> list) {
  // ...
}

Pros: Clients have a guarantee that the list parameter will not be mutated.

Cons: If the client has a List<Bar>, they must first convert it to an ImmutableList<Bar> before calling foo. This conversion wastes a small amount of time, and it is forced on clients whether they like it or not.


Note: For the purposes of this question, let's assume that all clients will have Guava's ImmutableList available, for example because the library and client code all belong to the same codebase that already uses ImmutableList elsewhere.

like image 258
k_ssb Avatar asked May 07 '20 07:05

k_ssb


People also ask

What is the advantage of having immutable collections and when we have to use the immutable collections?

The common use case for the immutable methods is a collection that is initialized from known values, and that never changes. Also consider using these methods if your data changes infrequently. For optimal performance, the immutable collections store a data set that never changes.

When should I use immutable objects?

Immutable objects can be useful in multi-threaded applications. Multiple threads can act on data represented by immutable objects without concern of the data being changed by other threads. Immutable objects are therefore considered more thread-safe than mutable objects.

What is mutable and immutable in programming?

Mutable is a fancy way of saying that the internal state of the object is changed/mutated. So, the simplest definition is: An object whose internal state can be changed is mutable. On the other hand, immutable doesn't allow any change in the object once it has been created.

What are mutable and immutable data types in Java?

The mutable objects can be changed to any value or state without adding a new object. Whereas, the immutable objects can not be changed to its value or state once it is created. In the case of immutable objects, whenever we change the state of the object, a new object will be created.


2 Answers

As the creator of the foo() API, this is none of your business. You take a list and you don't modify it, and that's it. Your code, in fact, doesn't care about the list's mutability (it's a concern of the caller): so document your intent and stop there.

If the caller needs to guarantee that the list will not be tampered with, they would create defensive copies not because you don't promise to leave the list unchanged, but because they need that guarantee.

It's following the same logic that we perform null checks in method implementations: it's needed because our code needs to be robust, not because the caller can send a null argument.

In other words, document your method as you intend to implement them, and leave it up to the caller to pick the list implementation. The reasons of their choices will vary (i.e., it won't always be only whether you'll modify the list).

like image 129
ernest_k Avatar answered Oct 12 '22 21:10

ernest_k


Leave it at List.

Here are some situations to consider:

  • Collections.synchronizedCollection does not modify the client's collection.
    • If it forced clients to input an immutable collection, there'd be no use in making it a synchronized collection, since an immutable collection would already be thread safe.
  • Collections.frequency does not modify the client's collection.
    • To check frequency, users would be forced to endure the excess overhead of transferring elements to a new collection.

These reasons aren't why the JDK doesn't expose an immutable interface. Those reasons are explained in the documentation. In the case of synchronizedCollection, although it doesn't modify the client's collection, it does return a modifiable view of the client's collection; some would say this function wouldn't apply here. However, frequency and other query functions still hold strong.

You shouldn't restrict clients for the purpose of trying to advertise safety and nothing more. There should be more justification, otherwise your attempt to help could be a burden on the client. In some cases, your goal can be contradictive to what the function/system is achieving, such as with the synchronizedCollection example.

It's good to encourage safety, but having your system force it onto your clients without the system benefiting from it would be abuse of power; that's not your decision to make.


ernest_k makes a really good point in his answer, suggesting that you need to analyze what your system should be in charge of, and what the client should be in charge of. In this case, it should be up to the client whether the collection is immutable or not, since your system doesn't care about mutability. As he put it, "it's none of your business", which I agree with.

like image 42
Vince Avatar answered Oct 12 '22 20:10

Vince