Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any way to DRY up these functions that convert numbers with defaults?

Tags:

scala

dry

I have a number of functions like this:

  // Convert a string to integer, defaulting to 0 if it fails
  def safeToInt(s: String): Int = try {
      s.toInt
    } catch {
      case _: NumberFormatException => 0
    }

  // Convert a string to long, defaulting to 0 if it fails
  def safeToLong(s: String): Long = try {
      s.toLong
    } catch {
      case _: NumberFormatException => 0
    }

  // Convert a string to double, defaulting to 0 if it fails
  def safeToDouble(s: String): Double = try {
      s.toDouble
    } catch {
      case _: NumberFormatException => 0
    }

Any way to make these cleaner? They essentially all do the same thing apart from one line.

like image 358
stevenheidel Avatar asked Mar 20 '23 05:03

stevenheidel


1 Answers

You can take advantage of Numeric to avoid duplicating the zero.

import scala.util.Try

def safeToNumeric[A: Numeric](f: String => A)(s: String): A =
  Try(f(s)).getOrElse(implicitly[Numeric[A]].zero)

val safeToInt = safeToNumeric(_.toInt)(_)
val safeToLong = safeToNumeric(_.toLong)(_)
val safeToDouble = safeToNumeric(_.toDouble)(_)

safeToInt("4") // 4
safeToDouble("a") // 0.0

Unfortunately Numeric doesn't give you the parsing method as well, but you can create the appropriate type class yourself ...

case class Parser[A](parse : String => A)

implicit val intParser = Parser(_.toInt)
implicit val longParser = Parser(_.toLong)
implicit val doubleParser = Parser(_.toDouble)

... and then you can write a single method that works for all of the types.

def safeTo[A: Parser : Numeric](s: String): A =
  Try(implicitly[Parser[A]].parse(s))
    .getOrElse(implicitly[Numeric[A]].zero)

safeTo[Int]("4") // 4
safeTo[Double]("a") // 0.0
like image 110
Chris Martin Avatar answered Mar 21 '23 18:03

Chris Martin