-3

I am reading CoreJava chapter on Lambda Expression and i couldn't understand the below paragraph.

In fact, conversion to a functional interface is the only thing that you can do with a lambda expression in Java. In other programming languages that support function literals, you can declare function types such as (String, String) -> int, declare variables of those types, and use the variables to save function expressions. However, the Java designers decided to stick with the familiar concept of interfaces instead of adding function types to the language

Can someone explain what a function literal or types is in terms of C++? I know the statement (string, string) -> int is allowed in C++ which allows to define return type. Java/C++ has parameter types too. So i am confused and not sure what the author is trying to say. Not sure if author is referring to closure for example in C++ closure has its state (captured variables). However it seems the author is comparing Java lambda expression with Scala but i don't know Scala at all.

Appreciate any insight.

yapkm01
  • 3,590
  • 7
  • 37
  • 62
  • 2
    A couple of paragraphs later it explains an example of how you can save a lambda as BiFunction and how it's unusable with Arrays.sort since it doesn't accept BiFunction. In a language that accepts more of the FP paradigm, you don't need an existing interface to save arbitrary lambdas, and the variable is accepted anywhere as long as the signature match, unrestricted by the interface hierarchy. – Martheen Aug 19 '23 at 21:36
  • 1
    In C++ `int (*) (string, string)` is an actual type; we can define variable with this type. In Java, this is not possible. We have to create a functional interface that represents the lambda-type. – Turing85 Aug 19 '23 at 21:37
  • @Turing85 I am still learning C++ as well :OP. From what i understand int(*)(string, string) is function pointer and yes can be assigned to a variable. This function pointer is not a lambda or can it be? In C++, a lambda is function object (internally an instance of unnamed class). So why is this being compared to Java that latter needs a functional interface to represent lambda-type? – yapkm01 Aug 19 '23 at 22:02
  • 1
    [`int (*func) (int, int) = [](int a, int b) { return a + b; }; stc::cout << func(1, 2) << std::endl;` (`onlinegdb.com`)](https://onlinegdb.com/OHsTeh827). Does this answer your question? – Turing85 Aug 19 '23 at 22:08
  • @Turing85 Ok. Which means Java lambda expression cannot be assigned to a var, so to speak. Did i get it right? – yapkm01 Aug 19 '23 at 22:33
  • 1
    No, they can. But we have to define the type of the variable first, through a functional interface. – Turing85 Aug 19 '23 at 22:35
  • @Turing85 Yes but what i meant was the 'var' keyword in Java. It cannot be inferred. Ok. I see what you're trying to say here. Appreciate much. – yapkm01 Aug 19 '23 at 22:36
  • 1
    Ah okay. thought you meant variables, not the `var` keyword. Yes, this is correct; lambdas cannot be assigned to `var`-variables. – Turing85 Aug 19 '23 at 22:38
  • 2
    @Turing85 that’s a matter of interpretation or formal nitpicking; you can’t use a lambda expression as variable initializer for a `var` declaration, but you can use an expression type casting a lambda expression as initializer, i.e. `var r = (Runnable)() -> {};` and you can assign a lambda expression to a `var` variable if it is not an initializer, i.e. `r = () -> System.out.println("hello");` after the previous example declaration works. – Holger Aug 21 '23 at 06:53

2 Answers2

1

Java only allows assignment of lambda expression to a functional interface. Other languages e.g. C++ does not have such restriction as long as the lambda expression can be converted to a match type.

Sample:

int (*func) (int, int) = [](int a, int b) { return a + b; }; 
std::cout << func(1, 2) << std::endl;

Reference: (Passing capturing lambda as function pointer)

yapkm01
  • 3,590
  • 7
  • 37
  • 62
0

The author seems either really confused (or using poor choice of words to explain something which is not conveyed with these words).

Is there even any fundamental difference between an instance of Java's Function<A, B> and Scala's Function1[A, B] ?

The essense of both is practically the same.

// Java Function

public interface Function<A, B> {

    A apply(B a);

}
// Scala Function1

trait Function1[-A, +B] { 
 
  def apply(a: A): B

}

These both create instances of an anonymous class (create by overriding interface Function<A, B> in Java and Function1[A, B]` in Scala).

For example, in Scala a type (A, B) => C is actually just a different way of writing the type Function2[A, B, C].

So... there is no effective difference between the following Scala and Java code

Function<String, Integer> func1 = new Function<String, Int>() {
  @Override
  public Integer apply(String s) {
    return Integer.parseInt(s);
  }
}
val func1 = new Function1[String, Integer] {
  def apply(s: String ): Integer =
    Integer.parseInt(s)
}

// exactly same but different sytax
val func2 = (s: String) => Integer.parseInt(s)

// exactly same but different syntax
val func3: String => Integer = 
  s => Integer.parseInt(s)

In Java, the lambda sytax ties into Function<A, B> interface which is similar to Scala where the lambda syntax ties into Function1[A, B] which in turn ties into the Java's Function<A, B>/ SAM depending on the context.

sarveshseri
  • 13,738
  • 28
  • 47