final
Java’s final modifier is backwards
In Java, there’s a modifier that can be applied to a variable, and it’s called final. Final can also be applied to classes and methods, to prevent overriding, which is kind of overloading the word. I don’t have a problem with that kind of final, except that I don’t agree that it’s good to use it liberally where you don’t design for inheritance up-front. This post is about final variables and immutable objects.
Good practice dictates that variables should always be marked final, except where the reference needs to be changed. This is true for class members, which should be assigned in instance initialization or a constructor, and can therefore be marked final. It’s true for method parameters, where it prevents you mistakenly thinking that Java is pass-by-value. And of course block-scoped variables should be final. All of this is good because it reduces mutable state at runtime, making your app less complex, more testable, and expresses your intent in compiler-enforceable constraints.
class Bear { final DateFormat df = new SimpleDateFormat("MMddyy"); final SalmonService ss; Bear() { ss = new HuntSalmonService(); } void eat(final Stream s) { final Integer hungerLevel = 10; ss.takeFish(s, hungerLevel); } }
The problem is, I only know one coder who is religious about declaring everything possible as final. Which sucks: if a variable is NOT marked final, this tells you nothing. Most likely, the coder didn’t write it because they were in a hurry or didn’t think it was needed, but they never modify the reference. The fact that Java makes you write this modifier everywhere is backwards, because you are rarely forced to use it (for use in anonymous inner classes). It would make more sense to use a modifier to note the exception rather than the rule, so we should have a mutable modifier instead. Now if you see a mutable List foo, you can bet the reference is really changed to another List later, since the developer bothered to mark it as mutable.
In Scala, you are forced to think about this, by marking your identifiers as a var or a val. Val’s are final, var’s are not. That’s good, Java should do that too. Now our Bear example is:
class Bear { DateFormat df = new SimpleDateFormat("MMddyy"); // non-mutable SalmonService ss; Bear() { // Without this, compiler complains that ss must be marked mutable ss = new HuntSalmonService(); } void eat(Stream s) { // re-assigning s here would be a compiler error mutable Integer hungerLevel; hungerLevel = 10; ss.takeFish(s, hungerLevel); } }
So far, this would be an easy change to the Java language, or something a new language could model.
There’s a second problem, however. I love to ask this in interviews: if something is marked final, can it be changed? It’s intentionally vague, and of course the answer is that the reference cannot change, but the value can. Immutability is important for the referenced object even more than for the reference, since immutable objects are thread-safe, can cache expensive operations, may be pooled, and it’s easier to reason about their state. They also have the same benefits as final variables – less mutable state at runtime is a Good Thing. Is there anything to be done at the language level to support the maxim, “Favor Immutability”?
Let’s imagine what it could look like. We’ll add the mutable modifier to a class that is mutable:
mutable class MyList<E> implements java.util.List<E> { List delegate = new ArrayList<E>(); public void add(E item) { delegate.add(item); } public E get(int index) { return delegate.get(index); } // More implementation for List methods ... } class YourList<E> implements java.util.List<E> { // We don't even want a mutator, but have to satisfy our interface void add(E item) { throw new UnsupportedOperationException(); } public E get(int index) { return delegate.get(index); } // More implementation for List methods ... } //reference and value are both mutable mutable List<Object> foo = new MyList<Object>(); foo = new YourList<Object>(); // now the value is immutable
This is no different from what Java does already: you have two classes, one that is mutable, and one that isn’t, or a method like Collections.unmodifiableList() that returns a wrapper around a list with exceptions thrown by the mutator methods – in the latter case, you don’t find out until runtime that mutation was attempted. Just like with the final modifier, the status quo is that everything is mutable, and thoughtful programmers sometimes use a utility method to produce immutable instances or have to write a second copy of their classes that lacks or hides the mutator methods. Note that there are lots of classes named “Immutable*” out there – maybe that’s backwards too. Again, we’d like the language to give us immutable objects unless we specifically ask for a mutable instance.
So we’ll just have the one MyList class, and we’ll need to mark the methods that are mutators. Those methods are only available, at compile time, if a mutable instance of the object was constructed. Since the mutable keyword is already in use for the referencing variable, we’ll need some other way to request mutable instances, maybe a mutable version of the new() operator. We can also mark methods as returning mutable instances, since we have made mutability part of our type system, and we don’t want callers to be able to cast an immutable return value into a mutable instance.
class MyList<E> implements java.util.List<E> { List delegate = new ArrayList<E>(); mutator void add(E item) { delegate.add(item); } public E get(int index) { return delegate.get(index); } // Return a mutable copy: public mutable MyList copy() { // call the copy constructor, // using the mutable() keyword instead of new() return mutable MyList(this); } // More implementation for List methods ... } mutable List<Object> foo = new MyList<Object>(); // Compile-time error: This instance of MyList is immutable foo.add("Not allowed"); foo.copy().add("Can do this"); foo = mutable MyList<Object>(); foo.add("Good");
Is this possible? I’m still pondering the implications. Here are a few:
- Can a non-mutator method call a mutator method? Probably that should be compile-time error.
- Should support reflection on whether an instance is mutable.
- Can the compiler figure out what are mutators without marking the method? Right now, if we forget to mark a method, it violates the immutability of our object. Or it could be reversed: a modifier could be required for the methods that are legal on immutable instances.
- Maybe if a newly created object is assigned to a mutable variable, it should be mutable? Then we could avoid this new brother of the new() operator.
I’d love to hear your comments.
About Me
Tweets
- @LaChilangringa thank you, he will be called Walter and might like trains or frogs. You were at the rally? What did your sign say? in reply to LaChilangringa 2010-11-06
- It says I'm not eligible to get a payout in the Buzz settlement. I'll have to settle for juggling with the Buzz developers. :) 2010-11-03
- It's Movember and you can sponsor my mustache. http://goo.gl/Z1O4 I miss the beard; It's very drafty on my face today. 2010-11-02
- Can 4 guys make themselves look enough like Mount Rushmore to fool Google Goggles image search? Love the demo slam. http://demoslam.com 2010-10-20
- Saw Dalai Lama on Thurs, running last 6mi of SF women's marathon with Peggy today. Too many crazy crowds this week! 2010-10-17
- Attn: people of the future. We wanted to avoid all that litter! It was our 2nd priority, right after annoying noises. http://bit.ly/cJzkGT 2010-10-09
- Headed to Hardly Strictly bluegrass in GG park. Elvis Costello free! 2010-10-03
- I vote that @TCooganPlants is having a rough week and deserves nachos. Who's with me? 2010-09-29
- More updates...
Powered by Twitter Tools