Reputation: 3061
I would like to check constructor arguments and refuse to construct throwing IllegalArgumentException in case the arguments set is not valid (the values don't fit in expected constraints). And same check should work while setting same argument set while modifying the object. How to code this in Scala?
scala> class Rectangle (var Length:Double, var Width:Double){
| if (Length <0)
| throw new IllegalArgumentException("The Length must be Non-negative")
| if (Width <0)
| throw new IllegalArgumentException("The Width must be Non-negative")
| def setLength(l:Double) = Length = l
| }
defined class Rectangle
scala> var R = new Rectangle (-9, -9)
java.lang.IllegalArgumentException: The Length must be Non-negative
at Rectangle.<init>(<console>:9)
scala> var R = new Rectangle (0, -9)
java.lang.IllegalArgumentException: The Width must be Non-negative
at Rectangle.<init>(<console>:11)
scala> var R = new Rectangle(9, 9)
R: Rectangle = Rectangle@1590164
scala> R.Length
res7: Double = 9.0
scala> R.Width
res8: Double = 9.0
scala> R.setLength(18)
scala> R.Length
res10: Double = 18.0
scala> R.setLength(-9)
// R.setLength should not the set the Length to -9. **************************
scala> R.Length
res12: Double = -9.0
Upvotes: 1
Views: 1874
Reputation: 53348
I don't like the answers mentioned so far. Your problem is that parameters must be valid to create an object. The other solutions abort object creation but in my opinion what you really want is not an abortion but some checks before creation of the object. To realize this you need factories:
object Rectangle {
def apply(length:Double, width:Double): Rectangle = {
require(length >= 0, "The Length must be Non-negative")
require(width >= 0, "The Width must be Non-negative")
new Rectangle(length, width)
}
}
class Rectangle private(val length:Double, val width:Double) {
def length_=(l: Double) = Rectangle(l, width)
}
The only problem here is, that we are not allowed to create a case class when we want to define our own apply-Method (with same method signature as the class constructor).
Upvotes: 2
Reputation: 38045
Mutable state is a bad idea, but if you do need it and don't want two points of validation, you can use a slightly modified solution of Prince John Wesley:
class Rectangle(l: Int, w: Int) {
private[this] var _length: Int = _
private[this] var _width: Int = _
def length: Int = _length
def width: Int = _width
def length_=(len: Int) { require(len > 0, "Invalid length: " + len + " < 0"); _length = len }
def width_=(wid: Int) { require(wid > 0, "Invalid width: " + wid + " < 0"); _width = wid }
length = l
width = w
override def toString = length + ", " + width
}
Upvotes: 2
Reputation: 67858
Must it be mutable?
case class Rectangle(length:Double, width:Double) {
if (length < 0)
throw new IllegalArgumentException("The Length must be Non-negative")
if (width < 0)
throw new IllegalArgumentException("The Width must be Non-negative")
def setLength(l: Double) = copy(length=l)
}
Upvotes: 2
Reputation: 63698
You need a property setter/getter methods.
class Rectangle(private var l: Int, private var w: Int) {
require(l > 0, "Invalid length: " + l + " <0 ")
require(w > 0, "Invalid width: " + w + " <0 ")
def length = l
def width = w
def length_=(len: Int) { require(len > 0, "Invalid length: " + len + " < 0"); l = len }
def width_=(wid: Int) { require(wid > 0, "Invalid width: " + wid + " < 0"); w = wid }
override def toString = length + ", " + width
}
Upvotes: 2