2014-12-08 Tweets

Changing Immutable Objects

Recently someone at work someone sent me a link to an article saying that getters and setters are evil by a guy named Yego256. He has a few other interesting posts about immutable objects here and here. They can be added to the list I made of pages about immutable objects here.

Hopefully Grails 3 will utilize immutability.

It takes a shift in mindset to start using immutable objects. Plus, in Java (and Groovy) a lot of web frameworks don’t utilize them, so people are not too familiar with them.

One issue some developers have is: Many things in the world are mutable. How can you make “changes” to immutable objects?

One answer is that you can use the values you don’t want to change to populate a new immutable object, and your variable/field name points to a new immutable object.

(If you can think of a better way to explain this, let me know. It’s kind of confusing to say that an immutable object is referenced by a “variable name”.)

I will demonstrate this with Groovy (using the annotations EqualsAndHashCode, Immutable and ToString). I made a class to model a state in the USA. States do not change their names, abbreviations or year they joined the union. But many of them have changed their capital cities. So we will make an object, and change its capital city while keeping everything else the same.

Here is our class:

package info.shelfunit.states

import groovy.transform.EqualsAndHashCode
import groovy.transform.Immutable 
import groovy.transform.ToString

@Immutable
@ToString( includeNames = true )
@EqualsAndHashCode
class USState {
    String name
    String abbrev
    String capital
    int yearJoined
}

Now let’s look at using it in a Groovy shell. The first capital of Illinois was a town called Kaskaskia, which no longer exists. Then it moved to Vandalia (which does still exist) and finally to Springfield.

I will try to change a few fields to prove the objects are immutable, and I will call hashCode() to show that we are dealing with different objects.

groovy:000> import info.shelfunit.states.*
===> [import info.shelfunit.states.*]
groovy:000> il = new USState( name: 'Illinois', abbrev: 'IL', capital: 'Kaskaskia', yearJoined: 1818)
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Kaskaskia, yearJoined:1818)
groovy:000> il.name
===> Illinois
groovy:000> il.name = "Indiana"
ERROR groovy.lang.ReadOnlyPropertyException:
Cannot set readonly property: name for class: info.shelfunit.states.USState
        at info.shelfunit.states.USState.setProperty (USState.groovy)
        at groovysh_evaluate.run (groovysh_evaluate:3)
        ...
groovy:000> il.toString()
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Kaskaskia, yearJoined:1818)
groovy:000> il.hashCode()
===> 1673606286
groovy:000> il = new USState( name: il.name, abbrev: il.abbrev, capital: 'Vandalia', yearJoined: il.yearJoined )
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Vandalia, yearJoined:1818)
groovy:000> il.abbrev
===> IL
groovy:000> il.abbrev = "WI"
ERROR groovy.lang.ReadOnlyPropertyException:
Cannot set readonly property: abbrev for class: info.shelfunit.states.USState
        at info.shelfunit.states.USState.setProperty (USState.groovy)
        at groovysh_evaluate.run (groovysh_evaluate:3)
        ...
groovy:000> il.toString()
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Vandalia, yearJoined:1818)
groovy:000> il.hashCode()
===> -934597459
groovy:000> il = new USState( name: il.name, abbrev: il.abbrev, capital: 'Springfield', yearJoined: il.yearJoined )
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Springfield, yearJoined:1818)
groovy:000> il.capital
===> Springfield
groovy:000> il.capital = "Homerville"
ERROR groovy.lang.ReadOnlyPropertyException:
Cannot set readonly property: capital for class: info.shelfunit.states.USState
        at info.shelfunit.states.USState.setProperty (USState.groovy)
        at groovysh_evaluate.run (groovysh_evaluate:3)
        ...
groovy:000> il.toString()
===> info.shelfunit.states.USState(name:Illinois, abbrev:IL, capital:Springfield, yearJoined:1818)
groovy:000> il.hashCode()
===> 213225124
groovy:000>

So we used the existing values to make new objects. The JVM used the same variable name (“il”) to refer to different immutable objects.

Here is the code without the output:

import info.shelfunit.states.*
il = new USState( name: 'Illinois', abbrev: 'IL', capital: 'Kaskaskia', yearJoined: 1818)
il.name // returns "Illinois"
il.name = "Indiana" // will cause groovy.lang.ReadOnlyPropertyException
il.toString()
il.hashCode()

// Change capital to Vandalia
il = new USState( name: il.name, abbrev: il.abbrev, capital: 'Vandalia', yearJoined: il.yearJoined )
il.abbrev // returns "IL"
il.abbrev = "WI" // causes groovy.lang.ReadOnlyPropertyException:
il.toString()
il.hashCode()

// Change capital to Springfield
il = new USState( name: il.name, abbrev: il.abbrev, capital: 'Springfield', yearJoined: il.yearJoined )
il.capital // returns "Springfield"
il.capital = "Homerville" // causes groovy.lang.ReadOnlyPropertyException:
il.toString()
il.hashCode()

You’re welcome.

2014-10-13 Tweets

2014-09-22 Tweets

When I Say “Groovy” or “Clojure”, I Mean “Groovy” or “Clojure”

Two languages that I am looking at these days (and would eventually like to work in) are Groovy and Clojure.

There is a site called Find Grails Jobs. Most of them are for jobs for which you would code in Groovy and/or in Grails.

But there are a few that are really Java jobs. They will mention a lot of Java technologies, and Groovy is mentioned as a “nice to have” way at the bottom. Are some firms hoping you will sneak Groovy into a Java shop? Or are they trying to pull a bit of a bait and switch? I think it might be the latter. I like Java, but I would prefer doing Groovy. If I want a Java job, I will look on a site about Java jobs.

There is no site devoted to Clojure jobs, but there is one called Functional Jobs. They have jobs for a lot of functional languages. So much for purity.

One ad said (and this is a direct quote): If you’re interested in functional languages like Scala, Swift, Erlang, Clojure, F#, Lisp, Haskell, and OCaml, then you’ll enjoy learning Flow.

First off: I tried googling a few combinations of “Flow”, “programming”, “language” and “software”. I could not find a page that appeared to be a home page for a language called “Flow”. I did find a few pages about “flow-based programming“, which I guess is like Dataflows in GPars.

But more to the point: If I am interested in Clojure, don’t tell me that I am interested in some other language that only exists at your company. If you feel that some obscure language is the best way to deliver your products, fine. But don’t tell me what I want. You decided to jump down the rabbit hole. You deal with it.

You’re welcome.

2014-09-15 Tweets