Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Popsicle Immutable

I am working on a problem where I need to load a large number of inputs to a problem, and process those inputs to create a 'problem space' (i.e. build data structures allowing efficient access to the inputs, etc). Once this initialization is complete, a multi-threaded process kicks off which uses the organized/processed inputs extensively in a concurrent fashion.

For performance reasons, I don't want to lock and synchronize all the read operations in the concurrent phase. What I really want is an an immutable object, safe to access by multiple readers simultaneously.

For practical reasons (readability & maintainability) I don't want to make the InputManager a true immutable object (i.e. all fields 'final' and initialized in construction). The InputManager will have numerous data structures (lists and maps), where the objects in each have many circular references to each other. These objects are constructed as 'true' immutable objects. I don't want to have a 14 argument constructor for the InputManager, but I do need the InputManager class to provide a consistent, read-only view of the problem space once constructed.

What I'm going for is 'popsicle immutability' as discussed by Eric Lippert here.

The approach I'm taking relies on using 'package visibility' of all mutating methods, and performing all mutable actions (i.e. construction of the InputManager) within a single package. Getters all have public visibility.

Something like:

public final class InputManager {  // final to prevent making mutable subclasses 
    InputManager() { ... } //package visibility limits who can create one
        HashMap<String,InputA> lookupTable1;
        ...

    mutatingMethodA(InputA[] inputA) { //default (package visibility)
        //setting up data structures...
    }

    mutatingMethodB(InputB[] inputB) { //default (package visibility)
        //setting up data structures...
    }

    public InputA getSpecificInput(String param1) {
        ... //access data structures
        return objA; //return immutable object
    }
}

The overall idea, if I haven't been clear enough, is that I'll construct the InputManager in a single thread, then pass it to multiple threads who will do concurrent work using the object. I want to enforce this 'two-phase' mutable/immutable object lifecycle as well as possible, without doing something too 'cute'. Looking for comments or feedback as to better ways to accomplish this goal, as I'm sure it's not an uncommon use case but I can't find a design pattern that supports it either.

Thanks.

like image 219
BrianV Avatar asked Oct 23 '22 05:10

BrianV


1 Answers

Personally I'd stay with your simple and sufficient approach, but in case you're interested, there is such a thing as a mutable companion idiom. You write an inner class that has mutators, while reusing all the fields and getters from the enclosing instance.

As soon as you lose the mutable companion, the enclosing instance it leaves behind is truly immutable.

like image 136
Marko Topolnik Avatar answered Nov 09 '22 12:11

Marko Topolnik