The Author Online Book Forums are Moving

The Author Online Book Forums will soon redirect to Manning's liveBook and liveVideo. All book forum content will migrate to liveBook's discussion forum and all video forum content will migrate to liveVideo. Log in to liveBook or liveVideo with your Manning credentials to join the discussion!

Thank you for your engagement in the AoF over the years! We look forward to offering you a more enhanced forum experience.

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.