I want to do some thing like the Kotlin’s [Function literals with receiver] i(https://kotlinlang.org/docs/lambdas.html#function-literals-with-receiver)
in Scala 2
Eg:
public object EmitterTest {
public abstract class EmitterOps<I, O> {
public fun emit(out: O): Unit = TODO()
public abstract fun apply(i: I): Unit
}
public inline fun <I, O> transform(crossinline emitterOps: EmitterOps<I, O>.(value: I) -> Unit): Unit = TODO()
public fun test() {
transform<Int, String> { value ->
//here the emit method is called on the receiver EmitterOps
emit("")
}
}
}
But I can’t do it in Scala 2
object Test {
def transform[I, O](emitterOps: EmitterOps[I, O]) = ???
def test(): Unit = {
// OK
val emitterOps: EmitterOps[Int, String] = new EmitterOps[Int, String] {
override def apply(in: Int): Unit = {
emit("hello")
}
}
// ----------
// ERROR
val emitterOps2: EmitterOps[Int, String] = (in: Int) => {
// ERROR here
emit("hello")
}
transform[Int, String](emitterOps)
// -------
// With context
val emitterWithContext: EmitterOps[Int, String] => EmitterOps[Int, String] = receiver => {
value =>
{
println(value)
receiver.emit(value.toString)
}
}
// bind to emitterOps
transform(emitterWithContext(emitterOps))
}
abstract class EmitterOpsWithContext[I, O] extends EmitterOps[I, O] {}
abstract class EmitterOps[I, O] {
def emit(out: O): Unit = {
???
}
def apply(in: I): Unit
}
}
Below is the best I can get.
object Main extends App {
trait FlowCollector[T] {
def emit(value: T): Unit
}
object FlowCollector {
implicit class FlowCollectorOps[T](collector: FlowCollector[T]) {
def emit(value: T): Unit = {
collector.emit(value)
}
}
}
case class Flow[T](data: Seq[T]) {
def collect(f: FlowCollector[T] => Unit): Unit = {
val collector = new FlowCollector[T] {
override def emit(value: T): Unit = {
println(value)
}
}
f(collector)
}
}
val flow = Flow(Seq(1, 2, 3, 4, 5))
flow.collect { implicit collector =>
collector.emit(1)
collector.emit(2)
}
}
Is there anyway in Scala I can achieve this, in the lambda block, I can refer to the other methods defined in that type.
This can’t be done in Java too, just tried, and below is the real code:
unsafeTransformUnordered[T](parallelism) { implicit emitter => out =>
import EmitterOps._
import EmitterUnsafeOps._
val future = f(out)
future.value match {
case Some(elem) => handleNow(elem)
case None => future.onComplete(handle(_))(pekko.dispatch.ExecutionContexts.parasitic)
}
}