20

The following Scala code works and can be passed to a Java method expecting a function. Is there a cleaner way to do this? Here's my first pass:

val plusOne = new java.util.function.Function[Int,Int] {
 override def apply(t:Int):Int = t + 1
 override def andThen[V](after:function.Function[_ >: Int, _ <: V]):
 function.Function[Int, V] = ???
 override def compose[V](before:function.Function[_ >: V, _ <: Int]):
 function.Function[V, Int] = ???
}

Here's my second pass - it uses a generic wrapper for the Java-8 Function interface to make the Scala syntax simpler:

// Note: Function1 is Scala's functional interface,
// Function (without the 1) is Java 8's.
case class JavaFunction1[U,V](f:Function1[U,V]) extends Function[U,V] {
 override def apply(t: U): V = f(t)
 override def compose[T](before:Function[_ >: T, _ <: U]):
 Function[T, V] = ???
 override def andThen[W](after:Function[_ >: V, _ <: W]):
 Function[U, W] = ???
}
val plusOne = JavaFunction1((x:Int) => x + 1)
val minusOne = JavaFunction1((x:Int) => x - 1)

Can we do better?

As a follow-up, is there any chance that Scala will someday use the invoke-dynamic op-code as Java 8 does for its first-class function application? Will that make everything magically work, or will there still need to be a syntactic conversion?

asked Mar 6, 2014 at 1:06

1 Answer 1

10

You can make the conversion implicit:

implicit def toJavaFunction[U, V](f:Function1[U,V]): Function[U, V] = new Function[U, V] {
 override def apply(t: U): V = f(t)
 override def compose[T](before:Function[_ >: T, _ <: U]):
 Function[T, V] = toJavaFunction(f.compose(x => before.apply(x)))
 override def andThen[W](after:Function[_ >: V, _ <: W]):
 Function[U, W] = toJavaFunction(f.andThen(x => after.apply(x)))
}
implicit def fromJavaFunction[U, V](f:Function[U,V]): Function1[U, V] = f.apply

You shouldn't actually need to override compose and andThen, but maybe Scala compiler doesn't know about Java 8 default interface methods yet. (EDIT: it should work in 2.10.3.)

Also, you should be able to assign Scala lambdas (i.e. x => ...) to Function and any other SAM types in Scala 2.11, and Java 8 lambdas to Function1. (EDIT: this actually got added in Scala 2.12, not 2.11.)

answered Mar 6, 2014 at 5:42
2
  • you should be able to assign Scala lambdas - This means that, in Scala 2.11, a Scala function can be passed as an argument for a Java8 Lambda? Commented Nov 8, 2016 at 2:36
  • Whether it can be passes as an argument depends on the lambda's type; if it's e.g. java.util.function.Consumer[scala.Function1[Integer, String]] then it can be done before 2.11 too. Commented Nov 8, 2016 at 6:31

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.