Case class constructor pre-process parameters without repeating argument list

I have a case class with a lot of parameters:

case class Document(id:String, title:String, ...12 more params.. , keywords: Seq[String]) 

      

For certain parameters, I need to do a string cleanup (trim, etc.) before creating the object.

I know I could add a companion object with an apply function, but LAST what I want is to write the TWICE parameter list in my code (apply the case class constructor and the companion object).

Does Scala provide anything to help me with this?

+3


source to share


2 answers


My general recommendations:

  • Your goal (data preprocessing) is the ideal use case for the companion object - so this is arguably the most idiomatic solution, despite the boilerplate.

  • If the number of case parameters is large, the constructor pattern definitely helps, since you don't have to remember the order of the parameters, and your IDE can help you call the builder member functions. Using named arguments for the case class constructor also allows for the order of random arguments, but as far as I know, there is no IDE autocomplete for named arguments => makes the builder class a little more convenient. However, the use of a builder class raises the question of how to deal with the specification of certain arguments — a simple solution can cause run-time errors; the type-safe solution is a little more verbose. The case class with default arguments is more elegant in this regard.

There is also this solution: add an extra flag preprocessed

with a default argument false

. Whenever you want to use an instance val d: Document

, you call d.preprocess()

, implemented with the copy method of the case class (to avoid having to re-enter all your arguments):

case class Document(id: String, title: String, keywords: Seq[String], preprocessed: Boolean = false) {
  def preprocess() = if (preprocessed) this else {
    this.copy(title = title.trim, preprocessed = true) // or whatever you want to do
  }
}

      



But: you cannot prevent the client from initializing preprocessed

on true

.

Another option would be to make some of your parameters a private val

and expose an appropriate getter for the preprocessed data:

case class Document(id: String, title: String, private val _keywords: Seq[String]) {
  val keywords = _keywords.map(kw => kw.trim)
}

      

But: pattern matching and default implementation toString

won't give you what you want ...

+2


source


After changing the context for half an hour, I looked at this problem with fresh eyes and came up with the following:

case class Document(id: String, title: String, var keywords: Seq[String]) {
  keywords = keywords.map(kw => kw.trim)
}

      



I just make the argument mutable by adding var

cleanup data to the class body.

Okay, my details are no longer immutable and Martin Oderski will probably kill the kitten seeing this, but hey .. I managed to do what I want to add 3 characters . I call it a victory :)

+1


source







All Articles