Isn’t Java a Civilised Language?
Although I’ve done lots of C/C++ in the past, I’ve been doing Java since 2001, so I’d virtually forgotten much of what I knew, and besides, Objective-C isn’t much like C++ anyway. The result is that you feel like you’ve washed up on a foreign shore unable to speak the language and you’re armed with nothing more than a sun tan and a dictionary.
In learning all this new stuff, I came to realise that Java is a VERY good language and the reason is, firstly and foremost, because you don’t have to think about memory allocation and deallocation, you can just get on with writing your application. In writing iOS applications in Objective-C, you have to both allocate memory for your objects and then clear up after yourself, returning your object’s memory back to the free-pool. This seems very old school for the second decade of the 21st century. Furthermore, having allocated memory for an object, you have to keep track of the number of references there are to it – a practice known as reference counting, something I first came across in my previous life as a C++ programmer. The fundamental idea here is that every time you create a new reference to an object, you increment the reference counter and when you’ve finished with the object reference you decrement its reference counter.
When the counter reaches zero, the the system releases the memory back to the free pool. In Objective-C, the function to decrement the reference count is called release; hence if Java had reference counting and if I wanted to, for example, ask an AddressService to find me an address, I’d need to do something like this:
// create an object and set the reference count to 1 AddressService addressService = new AddressService(); // Use the object Address address = addressService.findAddress(id); // pass it to a method model.addAttribute("address", address); // free the memory addressService.release();
That’s the simple scenario, but what happens if some method or other passes you an object reference as a method argument? In that case you have to decide how you’re going to hang on to it and there seem to be two ways of doing this. The first is to make a copy of the object and the second is to increment its reference count. Making a copy is probably the safest idea, but consumes more memory and will be slower, whilst incrementing the reference count is quick but not as safe as some other part of the program may get the reference counting wrong and decrement the count one too many times, which means that you’ve got a reference to some memory that may have been released, and when you try to access your released object your program will crash…. Again, if Java had reference counting then a Spring Controller request handler method would look something like this:
@RequestMapping(value = "/find", method = RequestMethod.GET) public String findAddress(@RequestParam("id") int id, Model model) { // increment the reference count - 'retain' is the Objective-C method for doing this. model.retain(); // create a new string object - with reference count of one String msg = new String().withFormat("Processing an address page request for address with id: " + id); // pass the string to the logger logger.info(msg); // release the string's memory msg.release(); AddressService addressService = new AddressService(); Address address = addressService.findAddress(id); model.addAttribute("address", address); addressService.release(); // finished with the model model.release(); return "address-display"; }
There are a couple of points to note here – firstly, the handler method is passed a model object, so I increment the reference count by calling retain and then call release on the model when I’m finished with it at the end of the method. Secondly, even when creating trivial objects, like a message string that’s passed to a logger, you have to apply the reference counting rules and free the memory once you’ve finished with it.
The example below demonstrates the alternative to incrementing the reference count: making your own copy of an object…
@RequestMapping(value = "/find", method = RequestMethod.GET) public String findAddress(@RequestParam("id") int id, Model model) { // increment the reference count - 'retain' is the Objective-C method for doing this. Model myModel = model.copy(); // As previous example // finished with the model myModel.release(); return "address-display"; }
These examples are only trivial, there’s a whole bunch of reference counting rules that you need to apply and if you get it wrong then Ka-Bam your program crashes and getting it wrong means either you try to access memory that’s already been freed, or slowly die due to a memory leak because you’ve forgotten to release some memory. Although I guess that the key point here is ownership: if you own an object, increment it’s reference count, when you’re finished with an object then decrement its reference count.
The code above is just a bit of scribble written to illustrate the point – it won’t compile. The code was actually taken from my Address sample on GitHub and in real life looks like this:
@RequestMapping(value = "/find", method = RequestMethod.GET) public String findAddress(@RequestParam("id") int id, Model model) { logger.info("Processing an address page request for address with id: " + id); Address address = addressService.findAddress(id); model.addAttribute("address", address); return "address-display"; }
…much smaller neater and more understandable. One last point, some of you will have noticed that in the reference counting example, I allocate (Objective-C word) a new AddressService – this is because iOS programming has nothing like dependency injection or a Spring framework, so you’re back to creating objects for yourself. (Note to the Guys at Spring: ‘Spring iOS’ – sounds like an idea to me…)
Those of you in the know will highlight the fact that Apple recently introduced something called ‘Automatic Reference Counting’. Whilst it isn’t garbage collection, it’s simplifies things in that iOS will now automatically keep track of your pointer references and free memory for you when the count reaches zero, which means that you don’t have to bother calling the retain and release methods.
Also, this blog isn’t trying to denigrate Objective-C – I quite like Objective-C. Its syntax seems rather arcane and feels verbose when compared to Java, but it forces you to be more disciplined in your programming technique, so if like me you believe that good programming is down to ‘clarity of thought’, then when writing an Objective-C program you have to think a little bit more clearly, and that I really like.
I also guess that a lot of readers might come up with a whole bunch of reasons as to why they think Java is a terrible language, and why their preferred language ‘does it better’, whatever it might be, so I’m looking forward to your comments…
Finally, I’m just a ‘newbie’ when it comes to iOS programming, so if any iOS/Objective-C masters come across this blog – please let me know where I’m wrong.
Reference: Isn’t Java a Civilised Language? from our JCG partner Roger Hughes at the Captain Debug’s Blog .
Seems like a lot of your points are on a garbage collected language vs a manually managed language and not necessary java vs objective c.
Plus, have you taken a look at ARC?
http://en.wikipedia.org/wiki/Automatic_Reference_Counting
Manual memory management is on the way out. And I find the ARC concept better than garbage collecting.
I fully agree with what you wrote about the benefits of automatic memory management (aka Garbage Collection). However, as the previous poster said, iOS now supports ARC – although I prefer real GC as it takes care of cycles etc. The most important thing however is: Even with Java and its magical GC, you can still end up having memory leaks if you are not careful. So regardless of the language, you should really know what you’re doing and therefore need a rough idea when memory is allocated and when it will be released. That being said, it’s of course… Read more »