pferrel pferrel - 4 months ago 16
Scala Question

Scala how to use defaults without redefining them

I have a function defined as:

def par(min: Int = -1, exact: Int = -1, auto: Boolean = false) = {
require(min > 0 || exact > 0 || auto, "Invalid argument")
OpPar(drm, minSplits = min, exactSplits = exact)
}


In another function that uses this I pass in Options for the
par
params. I would like to allow
par
to use it's own defaults but don't see how to do that in Scala (without ugly logic) so I have to redefine, in effect, the defaults like this.

drmARaw.par(
min = minPar.getOrElse(-1),// if par changes this may the be wrong default
exact = exactPar.getOrElse(-1),// if par changes this may the be wrong default
auto = autoPar.getOrElse(true))


If the defaults ever change this will pass the wrong defaults to
min
and
exact
. Using complicated logic I can decide which version of
par
to call based on which
Option
params are
nonEmpty
for
minPar
and
exactPar
but this is pretty ugly and would have to be written differently for every function with default params. This situation occurs with virtually every Scala lib out there. If they change the defaults and I don't notice it, my code will break.

The example above illustrates the problem but I'm looking for a Scala idiom that would cover every case where a function has defaults that could change. I want to write code that is independent of default param changes in lib functions.

Answer

So, as I understand it, you have three Options that you need to unpack and send as passed parameters, except if any option is None then the invoked method should use its own default value for the missing parameter.

It seems to me your only choice is brute force.

(minPar, exactPar, autoPar) match {
  case (Some(m),Some(e),Some(a)) => par(min=m, exact=e, auto=a)
  case (Some(m),Some(e),None)    => par(min=m, exact=e        )
  case (Some(m),None,   Some(a)) => par(min=m,          auto=a)
  case (Some(m),None,   None)    => par(min=m                 )
  case (None,   Some(e),Some(a)) => par(       exact=e, auto=a)
  case (None,   Some(e),None)    => par(       exact=e        )
  case (None,   None,   Some(a)) => par(                auto=a)
  case (None,   None,   None)    => par()
}

With 2 parameters it's easy. With 3 it's manageable. After that .... painful.