Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Method References like in Java 8 in Scala

In this Java class:

import java.util.function.*;

public class T {

    public String func(String a) {
        System.out.println("There we go: " + a);
        return a;
        }

    public static void main(String... args) {
        final Supplier<T> c = T::new;
        final BiFunction<T, String, String> f = T::func;

        final T t = c.get();
        final String v = f.apply(t, "something");

        System.out.println(v);
    }

}

I can get a method reference to the constructor of T and to the instance method func.

Is there a way to do the same in scala, i.e. to get

val c: () => T = ??? // default constructor of T as function
val f: (T, String) => String = ??? // instance method func of T as function

without wrapping them like that:

val c: () => T = () => new T
val f: (T, String) => String = (t, arg) => t.func(arg)

i.e. is there a way which is as elegant as the Java 8 way to get constructor and instance method references to obtain scala functions for these things?

like image 687
scravy Avatar asked Nov 03 '16 10:11

scravy


2 Answers

First, let's have a look at a literal translation of the Java code to Scala:

class T {
  def func(a:String) : String = {
    println(s"There we go: $a")
    a
  }
}
object T {
  def main(args: Array[String]) = {
    val supplier = () => new T
    val f = (t:T) => t.func _

    val t = supplier()
    val v = f(t)("something")
    println(v)
  }
}

In Scala, functions are first class citizens, hence there's no need to have particular constructions for "things that generate", like the Java Supplier, as it's modeled as a function: f: () => T (same thing goes for its counterpart, the Consumer as f: T => ())

We just said that functions are first class citizens, so let's see a version of the above using this paradigm:

object Tfunc {
  // let's remove the println side-effect from a function.
  val func: String => String = a => s"There we go: $a"

  def main(args: Array[String]) = {
    println(func("something"))
  }
}

In Scala, there's no counterpart to obtain a constructor reference, but if the aim is to use a functional approach, Scala objects offer a simple construct to hold functions and do not require to be instantiated.

like image 104
maasg Avatar answered Oct 31 '22 17:10

maasg


Exactly the way you do in java 8, you can't. For a class constructor I think there's no way to do that, except the way you did.

For functions you can use parameters placeholders which are "cleaner" in my opinion.

var t = new T()
var func = t.func _
func("a")

If you use a case class then you can use the apply method.

case class C(a: String)
var d = C.apply _
d("c")

You can use the apply function for normal classes too, but you have to implement it yourself. For case classes they are implemented automatically.

like image 43
Tiago Engel Avatar answered Oct 31 '22 18:10

Tiago Engel