Monday, June 1, 2009

Immutable Objects and Named Parameters in scala

--Updated--
Jorge Ortiz pointed out that 2.8 is already going to include a copy method in every case class:

Every case class already comes with a "copy" method defined something like:

def copy(x: Int = this.x, y: Int = this.y, z: Int = this.z) = {
Point3d(x, y, z)
}

And used like:

p1.copy(z = 2)

-Jorge Ortiz



Here's a cool way the named parameters feature being added in Scala 2.8 might help with immutable objects. It should help clients avoid errors when copying an immutable class, also it should end up hiding them from certain changes in that class.

//An overly simple example class
case class Point3d(x : Int, val y : Int, val z : Int) {
//Add method like this to make copying immutable classes easier
def copy (x : Option[Int] = None, val y : Option[Int] = None, val z : Option[Int] = None) = {
Point3d(x.getOrElse(this.x), y.getOrElse(this.y), z.getOrElse(this.z))
}
}

//Original class
val p1 = Point3d(1,1,1)

//"Old Way"
//notice every field is copied, this
//gets nasty as the class acquires more than just 3 fields
//Also notice how directly tied to the factory method
//this style is
val pOld = Point3d(p1.x, p1.y, 2)

//"New way"
//here we only care about the part of the
//class that we want to change. The class we are
//changing was refactored and additional fields were
//added to it, we would have to change all
the "Old Way"
//calls, however this call will still work fine.
val pNew = p1.copy(z=Some(2))

2 comments:

Jorge Ortiz said...

Every case class already comes with a "copy" method defined something like:

def copy(x: Int = this.x, y: Int = this.y, z: Int = this.z) = {
Point3d(x, y, z)
}

And used like:

p1.copy(z = 2)

Ben Jackman said...

That's very cool, I'll add your comment to the original post.