How to call returned function with implicits without assigning to val

Viewed 67

Suppose I have an object like:

object MyObj {
  def apply(args: List[String])(implicit v: Int): Unit => Int = (_: Unit) => args.length + v
}

If I want to MyObj.apply, I have to do:

implicit val v = 5
val myObj = MyObj(List("a", "b", "c"))
myObj()

But that feels redundant. What I want to be able to do is:

implicit val v = 5
MyObj(List("a", "b", "c"))()

Unfortunately, that doesn't seem to work. The system complains that I'm missing my implicit arguments, which makes sense, but is a bummer.

Is there any way that I can call the function returned from the apply method directly without first assigning it to a value?

2 Answers

This is a known issue in scala 2.XX and fixed in dotty.

Refer 3rd point from this ticket:

Passing explicit arguments to implicit parameters is written like normal application. This clashes with elision of apply methods. For instance, if you have

def f(implicit x: C): A => B then f(a) would pass the argument a to the implicit parameter and one has to write f.apply(a) to apply f to a regular argument.

https://github.com/lampepfl/dotty/issues/1260

Write either

MyObj(List("a", "b", "c")).apply()

or

MyObj(List("a", "b", "c"))(implicitly)()

By the way, accepting Unit is a little weird, usually Unit is returned. Maybe

object MyObj {
  def apply(args: List[String])(implicit v: Int): () => Int = () => args.length + v
}

looks more conventional (I guess Int is just for example, otherwise implicits of standard types like Int are not recommended either).


In Dotty

object MyObj {
  def apply(args: List[String])(using v: Int): Unit => Int = (_: Unit) => args.length + v
}

given Int = 5

MyObj(List("a", "b", "c"))(()) // 8

https://scastie.scala-lang.org/tpGE0JkWT3SuQ4ri0W9dNQ

Related