0

Is it possible to override a 'val' type on a Scala constructor?

Given a class such as this:

class GPPerson (id: Option[GPID], created: Option[DateTime], active: Boolean, primaryEmail: String)

I'd like to create a constructor that can essentially do this:

if (created == None) created = new DateTime

In other words, if a None value is supplies, replace it with a DateTime instance. The catch is, I'm trying to avoid using a companion object, and the 'created' object needs to be 'val' (can't make it a 'var').

2
  • Why are you avoiding using a companion object? That's kinda just... how you do it. Commented May 15, 2015 at 6:21
  • 1
    The companion object will complicate things. It's not impossible, but like I said "trying to avoid." These are TableQuery classes in Slick, and introducing a companion object causes implicit conversation to break... (eg., tupled() method is 'lost' because of apply() methods). That can be fixed by implementing an explicit tupled() BUT... this is basically a template for all of our models so I'm trying to keep it as simple as possible. Commented May 15, 2015 at 20:54

2 Answers 2

2

Constructor parameters may have a default value:

class GPPerson (id: Option[GPID], created: Option[DateTime] = Some(new DateTime), active: Boolean, primaryEmail: String)
// to instantiate it:
new GPPerson(id = Some(id), active = false, primaryEmail = myEmail)

You might want to reorder the parameters so optional parameters are the last ones, then you can omit the parameter name:

class GPPerson (id: Option[GPID], active: Boolean, primaryEmail: String, created: Option[DateTime] = Some(new DateTime))
// to instantiate it:
new GPPerson(Some(id), false, myEmail)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks Jhonny, excellent suggestions (I am trying to avoid changing the order, as our "standard" for our model objects is to have id and created date the first two parameters consistently – yes, it further complicates things).
1

One approach is

class GPPerson (id: Option[GPID], _created: Option[DateTime], active: Boolean, primaryEmail: String) {
  val created = _created.getOrElse(new DateTime)
}

Another:

class GPPerson (id: Option[GPID], created: DateTime, active: Boolean, primaryEmail: String) {
  def this(id: Option[GPID], _created: Option[DateTime], active: Boolean, primaryEmail: String) = this(id, _created.getOrElse(new DateTime), active, primaryEmail)
}

though for this specific case I'd go with @JhonnyEverson's solution.

3 Comments

Good suggestions – thanks for thinking outside the box a little bit! Unfortunately, this won't work since it's a model object and will then try to persist the _created... (trying to get exactly what we want is impossible because of the way Slick works, it seems a compromise between an "elegant" API versus a "simple" design pattern is required).
In the second option _created is not a field, and it should work. On the other hand, repeating such secondary constructors for all model objects would be really yucky. Could be avoided with a macro annotation, I guess, but this is far too heavyweight a solution when a default parameter would work as well :)
I agree... although tempting. And, you could mark the primary constructor argument as private, to hide the non-optional version ("class GPPerson private (id: ..." but... like you say, kind of yucky. Still, it does achieve the goal...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.