8

Here are two functions, one in kotlin.kt:

interface TraitA

fun <T : TraitA> foo(a: Any, f: (T) -> Unit) {
    TODO()
}

another adapter function in Scala.scala

import KotlinKt.foo

object Scala {
  def adapter[E <: TraitA](f: (E) => Unit): Unit = {
    foo[E](None, { a =>
      // Do something

      kotlin.Unit.INSTANCE
    })
  }
}

Till this moment, it compiles. But when I overload this function in Kotlin:

interface TraitA

fun <T : TraitA> foo(f: (T) -> Unit) {
    TODO()
}

fun <T : TraitA> foo(a: Any, f: (T) -> Unit) {
    TODO()
}

Scala fails to compile with the following error:

> Task :scala:compileScala
[Error] E:\Documents\Projects\Temp\kotlin-example\scala\src\main\scala\Scala.scala:5: missing parameter type
one error found

It tells me to add parameter type, so I added it:

import KotlinKt.foo

object Scala {
  def adapter[E <: TraitA](f: (E) => Unit): Unit = {
    foo[E](None, { (a: E) =>
      kotlin.Unit.INSTANCE
    })
  }
}

The compiler throws other error after the change:

[Error] E:\Documents\Projects\Temp\kotlin-example\scala\src\main\scala\Scala.scala:5: overloaded method foo with alternatives:
  (x$1: Object,x$2: kotlin.jvm.functions.Function1[_ >: E, kotlin.Unit])Unit <and>
  (x$1: kotlin.jvm.functions.Function1[_ >: E, kotlin.Unit])Unit
 cannot be applied to (None.type, E => kotlin.Unit)
one error found

I tried to construct a Kotlin Function1 "explicitly":

import KotlinKt.foo

import kotlin.jvm.functions.{Function1 => KF1}

object Scala {
  def adapter[E <: TraitA](f: (E) => Unit): Unit = {
    val kf: KF1[E, kotlin.Unit] = { e => f(e); kotlin.Unit.INSTANCE }

    foo[E](None, kf)
  }
}

It compiles and works well. But it is too circuitous, is there a prettier way to call foo[T](Any, Function1[_ >: T, kotlin.Unit])?

2
  • What version of scala? Commented May 9, 2020 at 21:22
  • Gradle 6.1, Kotlin 1.3.72, Scala 2.13.2 Commented May 10, 2020 at 4:05

1 Answer 1

4

Try to add implicit conversion

implicit def scalaToKotlin(u: Unit): kotlin.Unit = kotlin.Unit.INSTANCE

Then

def adapter[E <: TraitA](f: (E) => Unit): Unit = {
  foo(None, (e: E) => f(e))
}

compiles.

Scala 2.13.2, Kotlin 1.3.50, sbt 1.3.8 + kotlin-plugin 2.0.0.

Sign up to request clarification or add additional context in comments.

1 Comment

It solved my problem, thanks! But why can't I explicitly provide a type parameter 'E' for foo?

Your Answer

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.