views:

196

answers:

5

I'd like to be able to specify that an object's member variables are immutable once the object has been "initialized", which to me means after it has been injected with any dependencies, and has performed any other initialization operations that it can only perform after DI.

Are there languages that satisfy my interest - that formalize DI, initialization, and support immutability in this fashion? Maybe it's dumb to make them a part of a language; maybe not. I'm not sure.

Today I program in Java, but I can't use "final" nearly as much as I'd like, because those phases happen after the constructor has finished execution. Any advice on how to get what I want with Java? I guess I could have my objects implement a base class so that those phases happen before the constructor finishes, or use aspects to do the same.

Thoughts?

A: 

In Java, if you're using mutator methods to do your setting anyhow, it's pretty cheap (though also pretty ugly in my eyes) to add logic to prevent alterations once the object is initialized.

public void setMyProperty(String newValue) {
   checkInitialized();
   myProperty = newValue;
}

public void checkInitialized() {
   if ( initialized ) {
      throw new IllegalStateException("Setter called after initialization");
   }
}

At best though this is giving a dynamic check. It doesn't give you any static feedback over what you would have already had.

Mark Peters
+2  A: 

There are two main ways of producing immutable objects:

  1. use the builder/factory pattern - the builder may be mutable, but the objects it creates are immutable, usually implemented with final fields. You can also combine the two, so the object itself is used to build new instances, usually via "mutator" methods that change state on a separate, new instance. Spring's FactoryBean is an example of this.

  2. create a MutableObject subclass, which maintains a flag for mutable state. All your mutators check the mutable state before making any changes - if the object has been set to immutable, then the check throws an exception, otherwise the change goes ahead.

The first approach is quite Spring-centric, since it requires implmentation of a spring-specific interface. You can create factory beans that are regular beans, via factory-method/factory-bean attributes on a bean, which removes the spring dependency from your code.

Using the second approach is particularly useful with spring. You can instruct spring to call a method after bean initialization, e.g. seal() which seals the object - makes it immutable. Alternatively, you can implement a small BeanFactoryPostProcessor to do this automatically without having to remember to set the init-method="seal". on each immutable bean.

mdma
Your answer is helpful; I've selected the other one because it said "constructor injection", which has crystallized the issue a little better for me.
Ladlestein
I want to use "final" or, in another language, whatever mechanism signifies and enforces immutability. In Java, does Builder really help me? Isn't using constructor injection necessary to use final?
Ladlestein
The builder can use setter injection, and it produces the object using constructor injection. c.f. most FactoryBean implementations in Spring - they are configured using setter injection.
mdma
+1  A: 

In Java, you can use a builder to initialize an immutable object in its constructor, so you'd shy away from setters.

If you use Scala, though, immutability is the default.

Jordão
As I said above, how does Builder help, it seems to me that Builder isn't relevant, unless I'm using constructor injection.
Ladlestein
Exactly, that's why I said "shy away from setters".
Jordão
A: 

To specify that a class is immutable, you can use the @Immutable annotation.

You can see the Javadoc here.

This works well with the Findbugs plugin in Eclipse.

@Alexander:

As I understand him, he asked how to specify that a class is immutable. Not how to write an immutable class. This annotation can give you tool support to verify that you don't have a bug in your class that you claims are immutable.

A snippet from the Javadoc:

Of necessity this means that all public fields are final, and that all public final reference fields refer to other immutable objects

Espen
-1. Aahh! Is there a `@NoBugs` annotation? :)
Alexander Pogrebnyak
@Espen: Fair point. Downvote removed.
Alexander Pogrebnyak
+2  A: 

I guess it depends on what you want out of the immutability. If you want the guaranteed thread safety (where everything must be declared final, including the dependencies) then I think factory, builder or constructor injection are your only options.

If however you just want immutability of state, then declaring the state variables final should be enough. Even the immutable String class has a mutable field in its implementation (a cache of the hashcode value). As long as your code otherwise ensures that an instance is not available without injection, all should be well.

Yishai
I just want it to be clear which members are mutable and which are not.Strange, but I never thought about how setter injection is incompatible with immutable state. Well, I wasn't thinking about it when I wrote the question, at least :-)
Ladlestein