Vidya
Vidya

Reputation: 30320

Compiler Not Resolving Default Typed Function Parameter

I have a function that takes a typed sort function as a parameter, and I want this sort function to have a default parameter:

def foo[T](sort: MyObject => T = _.position)(implicit o: Ordering[T])

MyObject.position returns an Int.

Understandably, I am getting this error:

Expression of type (MyObject) => Int doesn't conform to expected type (MyObject) => T

OK, but I was hoping that the compiler would figure out that in the default case T is Int and check that an Ordering[Int] is available in implicit scope.

How can I help the compiler resolve this?

Upvotes: 1

Views: 33

Answers (1)

Kolmar
Kolmar

Reputation: 14224

You can use an overloaded function with and without an argument:

def foo(): FooResult = foo(_.position)
def foo[T](sort: MyObject => T)(implicit o: Ordering[T]): FooResult = ???

I can think up one way though, how to actually do it with a non-overloaded function (and some boilerplate).

You can take a special argument, which packs the sort function, the ordering and even the implementation of foo, and provide an implicit conversion from a suitable function to this argument. This is basically an application of the Magnet pattern.

sealed trait Magnet {
  type T

  val sort: MyObject => T
  implicit val o: Ordering[T] 

  def fooImpl = ???
}

object Magnet {
  implicit def fromSort[T0](sortArg: MyObject => T0)(implicit ordArg: Ordering[T0]): Magnet = 
    new Magnet {
      type T = T0

      val sort = sortArg
      val o = ordArg
    }
}

def foo(sort: Magnet = (_: MyObject).position) = sort.fooImpl

One drawback is that this loses the expected type for the argument, so you have to specify the type of the argument of the sort function.

The usability for your case is questionable, but it's still an interesting solution nevertheless and may be useful in other situations.

Upvotes: 2

Related Questions