Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Properties Question

I'm still learning Scala, but one thing I thought was interesting is that Scala blurs the line between methods and fields. For instance, I can build a class like this...

class MutableNumber(var value: Int)

The key here is that the var in the constructor-argument automatically allows me to use the 'value' field like a getter/setter in java.

// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)

If I want to add constraints, I can do so by switching to using methods in place of the instance-fields:

// require all mutable numbers to be >= 0
class MutableNumber(private var _value: Int) {
    require(_value >= 0)

    def value: Int = _value
    def value_=(other: Int) {
        require(other >=0)
        _value = other
    }
}

The client side code doesn't break since the API doesn't change:

// use number...
val num = new MutableNumber(5)
num.value = 6
println(num.value)

My hang-up is with the named-parameter feature that was added to Scala-2.8. If I use named-parameters, my API does change and it does break the api.

val num = new MutableNumber(value=5)  // old API
val num = new MutableNumber(_value=5) // new API

num.value = 6
println(num.value)

Is there any elegant solution to this? How should I design my MutableNumber class so that I can add constraints later on without breaking the API?

Thanks!

like image 769
shj Avatar asked Nov 11 '10 20:11

shj


1 Answers

You can use the same trick that case classes do: use a companion object.

object Example {
  class MutableNumber private (private var _value: Int) {
    require (_value >= 0)
    def value: Int = _value
    def value_=(i: Int) { require (i>=0); _value = i }
    override def toString = "mutable " + _value
  }
  object MutableNumber {
    def apply(value: Int = 0) = new MutableNumber(value)
  }
}

And here it is working (and demonstrating that, as constructed, you must use the object for creations, since the constructor is marked private):

scala> new Example.MutableNumber(5)
<console>:10: error: constructor MutableNumber cannot be accessed in object $iw
   new Example.MutableNumber(5)
   ^

scala> Example.MutableNumber(value = 2)
res0: Example.MutableNumber = mutable 2

scala> Example.MutableNumber()
res1: Example.MutableNumber = mutable 0
like image 114
Rex Kerr Avatar answered Sep 22 '22 07:09

Rex Kerr