2

I have a function exec which accepts 3 parameters and applies a function f passed as first argument to the other two - p1 and p2.

  def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)

Everything works fine if I declare in advance a function which will be passed as an argument.

Somehow compiler can infer types for arguments of eq or in other words it can figure out that whatever in this case is Int

  // declaring a function with type parameter (polymorphic method)
  def eq[whatever](p1: whatever, p2: whatever) = p1 == p2
  // using a declared function
  println(exec(eq, 10, 10))

It also works fine if I explicitly specify Int as shown below

  // specifying type explicitly in function literal
  println(exec((p1: Int, p2: Int) => p1 == p2, 10, 10))
  // specifying type parameter
  println(exec[Int]((p1, p2) => p1 == p2, 10, 10))

Question 1

Is it possible to get below working?

println(exec((p1, p2) => p1 == p2, 10, 10))

For example, by using implicits, defining exec differently or using some other way making it possible for compiler to infer types of p1 and p2 so that it does not fail with missing parameter type.

So no explicit type hints or declared methods are used.

Question 2

How does compiler infer types for eq and why it works for expressions like p1 == p2 or p1 != p2 but fails for p1 >= p2 (error is value >= is not a member of type parameter whatever)?

Mario Galic
  • 47,285
  • 6
  • 56
  • 98
Dr Y Wit
  • 2,000
  • 9
  • 16

2 Answers2

3

Question 1 Is it possible to get below working?

If you can rewrite exec like this:

def exec[T](p1: T, p2: T)(f: (T, T) => Boolean) = f(p1, p2)

Then, the compiler will already know the input type of the function.
So, you will be able to call it like this:

println(exec(10, 10) { case (p1, p2) => p1 == p2 })

This is a common idiom, to put plain parameters first and then a function on a single parameter group.

How does compiler infer types for eq and why it works for expressions like p1 == p2 or p1 != p2 but fails for p1 >= p2

Because, Scala has universal equality (which is one of the things people most criticize of the language, but it was necessary for Java interop).

So, you can always compare two objects of any class for equality.
That is because equality is defined in the Any superclass as follows.

class Any {
  def equals(other: Any): Boolean
}

But, ordering is not universal.
If you want, you may want to write a generic function which works for any type as long as there is an order for such type, you may be interested in the Ordering - typeclass.
But that is topic for another question.

  • 1
    Thanks! One minor addition - there is no need in anonymous partial function. It works like this as well `println(exec(10, 10)((p1, p2) => p1 == p2))`. – Dr Y Wit Jun 01 '20 at 18:32
  • 1
    Quick description why currying is needed in Scala 2 in such cases for type derivation - https://docs.scala-lang.org/tour/multiple-parameter-lists.html – Dr Y Wit Jun 01 '20 at 19:12
3

Scala 3 (dotty) will be able to infer the types in exec without having to rely on multiple parameter lists to help inference

scala> def exec[T](f: (T, T) => Boolean, p1: T, p2: T) = f(p1, p2)
     | exec((p1, p2) => p1 == p2, 10, 10)
def exec[T](f: (T, T) => Boolean, p1: T, p2: T): Boolean
val res0: Boolean = true
Mario Galic
  • 47,285
  • 6
  • 56
  • 98