2

I'm beginning an objective-c project. I have a question regarding immutability. Is it worth trying to make objects immutable whenever I can? If I update a field, I have to return a pointer to a new object and dealloc the old. If I do this often, there might be performance issues. Also, the code will probably be more verbose. There are undoubtedly other considerations. What do you think?

Edit: Let me clarify what I mean when I write "update a field". Normally, when you update a field you call a setter and just change the value of the field. If the object is immutable, the setter does not actually update the field, instead it creates a new instance, with all the fields having the same value, except for the field you are trying to update. In java:

class User{
   private String firstName;
   private String lastName;
   public User(String fn, String ln){ firstName = fn; lastName = ln; }

   public User setFirstName(String fn){ return new User(fn, lastName); }

}
yalis
  • 1,508
  • 1
  • 16
  • 24
  • By definition, you couldn't update an immutable object's "field", so it's not really clear what you're asking. Also, the question of mutability is not specific to the Objective-C language, but is rather a general software design consideration. – Shaggy Frog Apr 15 '11 at 01:54
  • So the setter method would not actually be a mutator but a constructor instead? That seems… odd. –  Apr 15 '11 at 02:19
  • I'm with Bavarious. Having a setter return an object is very odd, even in Java, and in ObjC is certainly against convention and KVC. The correct name for this method should be `userByChangingFirstName`. But the point is valid about what it means to "mutate" an immutable class. Consider `stringByAppendingString:`. It is a very common functional pattern. – Rob Napier Apr 15 '11 at 02:35
  • Yeah, I agree. I just dashed out an example. Maybe User replaceFirstName(String fn). – yalis Apr 15 '11 at 03:01

4 Answers4

4

Use immutable objects whenever possible, due to the performance overhead of mutable objects.

Edit: Well, usually the above should be true, but it seems there are situations where NSMutableArray performance is actually better then NSArray. Read some more about it on the Cocos2d site:

Read some more about mutability on CocoaWithLove (great weblog for Mac / iOS developers so put it in your favorites!).

I'd also like to add that a lot of objects have the -mutableCopy instance method, this is an easy to use method to retrieve a mutable copy from an immutable objects, like a NSArray or NSString, e.g.:

NSArray *array = [NSArray arrayWithObjects:@"apple", @"pear", @"lemon"];
NSMutableArray *mutableArray = [array mutableCopy];
// remember to release the mutableArray at some point 
//    because we've created a copy ...

Just remember in some situations a mutable object is easier to use, for example for a UITableView that makes use of a datasource that is subject to a lot of changes over time.

Wolfgang Schreurs
  • 11,779
  • 7
  • 51
  • 92
  • Did you mean to write "Use mutable object whenever possible, due to the performance overhead of immutable objects"? – yalis Apr 15 '11 at 02:09
  • Usually immutable (i.e.: not mutable) objects should have less overhead. – Wolfgang Schreurs Apr 15 '11 at 02:10
  • I am curious. Why do you think immutable objects have less overhead? One problem in languages that emphasize immutability (such as clojure, scala, haskell and functional programming languages in general) is that updating a data structure can be slow if not done correctly. For example, adding an element to a list means returning a new list, and the naive (and inefficient) way to do this is to return a copy of the list. – yalis Apr 15 '11 at 02:20
  • @yalis: I have to admit that I'm not 100% sure why immutable objects in general seem to perform better in the Cocoa framework (I could make some guesses though), but I've seen performance comparisons in the pasts on internet, therefore I considered it good practice to use immutable objects whenever possible and mutable only when necessary. – Wolfgang Schreurs Apr 15 '11 at 02:38
2

Whether mutable or immutable objects are best is very situation dependent, so it's best if you give a more concrete example to discuss. But here are some things to think about.

  • Often object properties are somehow inter-related. For instance, a Person might have a givenName and surname, but might also have a fullName that combines those two, and it might have a nameOrder that indicates which comes first. If you make Person mutable, then there can be points in time that fullName might be incorrect because you have changed the surname but not the givenName (perhaps one of them is still nil). You now need a more complex interface to protect you against this.

  • If other objects use this mutable Person, they have to employ KVO or notifications to find out when it has changed. The fact that interrelated fields might change independently can make this complex, and you find yourself writing code to coalesce the changes.

  • If some combinations of properties are illegal, mutable objects can be very hard to error check. An immutable object can do all of its checking when it is constructed.

  • There are some middle-grounds between mutable and immutable. In the above example of Person and various name properties, one way to simplify much of it is to let Person be mutable, but create a separate immutable Name object that contains the various parts. That way you can make sure that the entire name is mutated in an atomic way.

  • Immutable objects greatly simplify multi-threaded code. Mutable objects require a lot more locking and synchronization, and this can significantly hurt performance and stability. It's very easy to screw this code up. Immutable objects in comparison are trivial.

  • To your point about creating and throwing away objects, immutable objects also give the opportunity for sharing, which can make them very efficient if there are likely to be many objects pointing to the same data contents. For instance, in our Person example, if I make an immutable Address object, then every person who lives at the same address can share the same object. If one changes their address, this doesn't impact all the others.

  • As an example of the above, my code has a lot of email addresses in it. It's extremely common for the same string to show up over and over again. Making EmailAddress immutable, and only allowing it to be constructed with +emailAddressForString: allows the class to maintain a cache and this can save significant memory and time to construct and destroy string objects. But this only works because EmailAddress is immutable.

Anyway, my experience is that it's often better to err towards immutable data objects for simplicity, and only make the mutable when immutability creates a performance problem. (Of course this only applies to data objects. Stateful objects are a different thing, and of course need to be mutable by their nature, but that doesn't mean that every part of them must be mutable.)

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • Thanks for mentioning multithreaded code; I was about to do that. –  Apr 15 '11 at 02:24
  • I agree with all your points in general. And languages like clojure go to great lengths to make efficient immutability the norm. For example a map in clojure is a stateful object with all the semantics of immutability (you don't update in place, but return a copy). But objective-c is not geared towards immutability and you have to roll your own immutable classes. But if I am reading you correctly you agree that making objects immutable in objective-c is worth the effort, unless it obviously does not make sense. – yalis Apr 15 '11 at 02:50
  • I'm saying that immutability often simplifies the code, and that simplicity has many advantages, one of which can be performance. There are cases when immutability can significantly harm performance, and you should optimize with different data structures when that happens, and of course when the object's nature is stateful. So yes, making objects, particularly value objects, immutable is generally worth the effort. – Rob Napier Apr 15 '11 at 18:15
1

As in any other imperative language: it depends. I've seen decent boosts in code performance when we use immutable objects, but they're also usually infrequently-modified objects, ones which are read out of an archive or set by a user and then passed around to all different bits of code. It doesn't seem worth doing this for all your code, at least not to me, unless you plan on heavily leveraging multiprocessing and understand the tradeoffs you're making.

Ben Stiglitz
  • 3,994
  • 27
  • 24
0

I think the bigger immutability concern is that if you've done good design to keep your data marked immutable when it is such, and mutable when it is such, then it's going to be a lot easier to take advantage of things like Grand Central Dispatch and other parallelization where you could realize far greater potential gains.

As a side note, moving to Objective C from Java, the first tip I can give you is to ditch the notion of public and private.

Nektarios
  • 10,173
  • 8
  • 63
  • 93