Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any way to set a default value to generic type variable in Scala?

Tags:

scala

I want to set a default value to variable. But my Scala compiler says:

Error:(20, 16) unbound placeholder parameter
    val p: T = _
               ^

Here is the code.

object InverseFunctionsExample extends App {

  type D = Double

  def f(x: D): D = 5 * x + 10
  def g(x: D): D = 0.2 * x - 2

  printMessage(isInversible(f, g))

  def printMessage(inv: Boolean): Unit = {
    if (inv) print("YES!") else print("NOPE!")
  }

  def isInversible[T](f: (T) => T, g: (T) => T): Boolean = {
    val p: T = _
    if (f(p) == g(p))
      true
    else
      false
  }
}

Is it possible to initialize a val p with default value somehow?

like image 804
barbara Avatar asked Sep 28 '22 11:09

barbara


2 Answers

Only var fields (not local variables) can be initialized in this way. If you want to define "default values" for different types, the standard approach is the type-class pattern:

case class Default[T](value: T)

object Default {
  implicit val defaultInt: Default[Int] = Default(0)
  implicit val defaultString: Default[String] = Default("")
  ...
}

def isInversible[T](f: (T) => T, g: (T) => T)(implicit d: Default[T]): Boolean = {
  if (f(d.value) == g(d.value))
    true
  else
    false
  // or just f(d.value) == g(d.value)
}
like image 111
Alexey Romanov Avatar answered Oct 13 '22 13:10

Alexey Romanov


You can use reflection to instantiate a new instance of a class, but that's probably not going to be very useful for you here:

class Foo
classOf[Foo].getConstructor().newInstance()

You can read about the reflection API to see you how you can pick a suitable constructor here.

You could also have a parameter that specifies how to instantiate a new instance:

def isInversible[T](f: T => T, g: T => T, def: => T) = f(def) == g(def)

Since this looks like an inherently math-oriented problem, you might be interested in the Numeric type, which can help facilitate this kind of logic generically for different number types. For example:

def intersectAtOrigin[T](f: T => T, g: T => T)(implicit n: Numeric[T]) = {
    val zero = n.zero
    f(zero) == g(zero)
}

And then you can do:

def f(x: D): D = 5 * x + 10
def g(x: D): D = 0.2 * x - 2
intersectAtOrigin(f, g) //false, working with Doubles
intersectAtOrigin[Int](_ + 1, x => x * x + x + 1) //true, working with Ints

You can read more about Numeric in the docs here.

like image 36
Ben Reich Avatar answered Oct 13 '22 12:10

Ben Reich