Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modifying case class constructor parameter before setting value

Is there a way in Scala to modify a parameter passed to a single-argument case class constructor / apply() method before it becomes a val? E.g.

case class AbsVal private(aVal: Double)

object AbsVal {
    def apply(aVal: Double): AbsVal = AbsVal(Math.abs(aVal)) // doesn't compile
}

This fails of course with ambiguous reference to overloaded definition. I thought maybe I could trick it with named parameters (and different parameter names for the constructor vs apply()), but that doesn't work either.

Of course instead of apply() I could just have the private constructor and a factory method, but it's annoying to have to litter the code with AbsVal.make(x) instead of just AbsVal(x).

like image 205
David Moles Avatar asked Jun 16 '14 00:06

David Moles


2 Answers

abstract case class AbsVal private(value: Double)

object AbsVal {
  def apply(value: Double): AbsVal = new AbsVal(Math.abs(value)) {}
}

Abstract case classes don't have an apply method automatically generated in their companion object. This lets us create our own. We have to create another class to inherit from the case class (anonymous, here), but the toString method generated for the case class will still display it as an AbsVal, so this should be invisible as well. A copy method is not automatically generated for abstract case classes, but for a class with a single parameter like this it wouldn't be useful anyway (and it can always be defined manually, see LimbSoup's answer).

Case class inheritance is usually a bad idea, but because of the private constructor the only subclass that will exist will be the anonymous one we define, so in this instance it is safe.

like image 151
wingedsubmariner Avatar answered Nov 16 '22 17:11

wingedsubmariner


it's annoying to have to litter the code with AbsVal.make(x) instead of just AbsVal(x)

This is an extremely subjective point. Throughout different languages it is a common wisdom to prefer descriptive names to overloaded definitions, since they tend to introduce ambiguity. Yours is a perfect example of such a case.

Hence, AbsVal.make(x) is the correct way to go in your situation. Although I'd rather name it something like AbsVal.abs(x).

like image 3
Nikita Volkov Avatar answered Nov 16 '22 16:11

Nikita Volkov