242124 (5) [Avatar] Offline
#1
In MEAP V13 Listing 3.5 we have

sealed trait Account {
  def no: String
  def name: String
  def dateOfOpen: Option[Date]
  def dateOfClose: Option[Date]
  def balance: Balance
}

final case class CheckingAccount private (no: String, name: String,  dateOfOpen: Option[Date], dateOfClose: Option[Date], balance: Balance) extends Account

final case class SavingsAccount private (no: String, name: String, rateOfInterest: Amount, dateOfOpen: Option[Date], dateOfClose: Option[Date], balance: Balance) extends Account

object Account {
  // smart constructors here
  ...
}

(this is what is in the book, the code on github is a bit different)

The text essentially states that the constructor is private so that an invalid instance can't be made. The problem is that one can still use the case class' copy method and end up with an invalid instance.

It seems we could override copy and delegate to our smart constructor. It feels like that should always be safe assuming the smart constructor has no side effects (which it shouldn't). Does that sound right?

Also, private keeps you from calling "new CheckingAccount(...)", but the case class' apply() is still there. Is this a similar case as before where we should override apply in the companion object and call the smart constructor (or make them one in the same)?

I also found this, which is a bit more complicated and I'm unsure what the drawbacks or advantages might be: http://stackoverflow.com/a/20031021/3705269.
trait Meter {
  def m: Int
}

object Meter {   
  def apply(m: Int): Meter = { MeterImpl(m) }
  private case class MeterImpl(m: Int) extends Meter { println(m) }
}

Well, I guess one drawback is we don't have an ADT anymore I don't think.

What is the best solution here for all problems? (The problems being controlling: new, apply, and copy)

Thanks.
Debasish Ghosh (116) [Avatar] Offline
#2
I agree with your thoughts of having the `apply` and `copy` delegate to the smart constructor. In fact I may add that to the online code as well. But I think still there are some hairy cases as in http://stackoverflow.com/questions/19462598/scala-case-class-implementation-of-smart-constructors.

Thanks.