<p>In Java, there are &quot;SAM-interfaces&quot; which are used as &quot;types&quot; for lambda expressions. In Haskell, there are dedicated types for functions. In Rust, there are no types for functions, but instead there are traits for functions.</p>
<p>What are the differences between these approaches? For a new language, which one should be chosen?</p>

<rust><haskell><java>
What are the advantages of having first-class functions versus having only anonymous class with fancy sugars?
<h1>First class functions are cleaner</h1>
<p>If your closures/lambdas are SAM interfaces, in production you often end up writing a lot of duplicate interfaces for the same functions. As a Java example, one library might have a <code>StringPoster</code> while another uses <code>Consumer&lt;String&gt;</code>, even though they are the same. In Kotlin, both would likely be <code>(String) -&gt; Unit</code>, perhaps with type aliases, allowing for much greater consistency and clarity.</p>

CC BY-SA 4.0
2023-05-16T22:57:27.333Z
2023-05-16T22:57:27.333Z
Seggan
CC BY-SA 4.0
2023-06-29T05:00:23.517Z
I don't think this is so much a problem of having SAM interfaces vs. first-class functions, but with the standard library providing standard interfaces. While the standard interfaces in `java.functional` were added at the same time as lambdas and streams, there is nothing inherently tying them together. They could have been provided from day 1. For example, in Scala, *every* object that has an `apply` method can be called like a function, but the majority of them still *choose* to inherit from `Function` even though it is not necessary. Conversely, library authors choose to take `Function`s …
Jörg W Mittag
CC BY-SA 4.0
2023-06-29T05:00:37.050Z
… as arguments, even though they could easily define their own types. It is basically just exploiting library authors' laziness.
Jörg W Mittag
CC BY-SA 4.0
2023-06-29T13:42:10.287Z
@JörgWMittag apologies, I dont get your argument. Can you rephrase it?
Seggan
CC BY-SA 4.0
2023-07-29T16:30:05.787Z
IIRC this was actually an explicit decision in Java when they added lambdas. Besides integrating better into the existing language, they rationalize that complicated function types can easily lose their semantic meaning. And if you add new arguments to your StringPoster you don't have to edit the name of the type everywhere it appears.
Criticize SE actions means ban
<p>One advantage to the Java SAM approach is that while the implementation of the function-interface only needs to implement one method (and this can be made compact through lambdas), the interface itself may contain additional default methods for composing or otherwise modifying the behaviour.</p>
<p>For example, if a method takes a <code>Predicate&lt;T&gt;</code>, then the caller just needs to pass something that takes a <code>T</code> and returns a <code>boolean</code>... but once you have an <em>instance</em> of the <code>Predicate</code>, you can do things like:</p>
<ul>
<li><code>newPredicate = predicate.negate()</code></li>
<li><code>newPredicate = predicate1.and(predicate2)</code></li>
<li><code>newPredicate = predicate1.or(predicate2)</code></li>
</ul>
<p>Similarly, a <code>Function&lt;V,R&gt;</code> only needs to take a <code>V</code> and return an <code>R</code>, but once you have one, you can do:</p>
<ul>
<li><code>newFunction = function1.andThen(function2)</code></li>
</ul>
<p>And to be clear - it's not that these <em>couldn't</em> be done without SAM types. But it does mean that these kinds of operation can be tailored to the needs of a particular interface... e.g. the predicate case provides operations which make sense for a predicate, but not necessarily for an arbitrary function that returned a boolean.</p>

CC BY-SA 4.0
2023-07-27T22:35:52.567Z
2023-07-27T22:35:52.567Z
Simon Geard
CC BY-SA 4.0
2023-07-27T22:51:13.780Z
Another neat thing about such functional interfaces is, if it makes sense to do so, you can write a proper class instead of just a lambda expression, and provide specialised implementations of `negate`, `and` and `or` which might be more performant than the default implementations.
kaya3
CC BY-SA 4.0
2023-07-31T00:23:57.117Z
Yes... one util function I use regularly wraps a `Function<V,R>` and a `Map<V,R>`, invisibly caching the results of the former using the latter. Very handy for short-lived caching, e.g. avoiding unnecessary database hits while processing a list that may contain a lot of repeated references.
Simon Geard
<p>I believe the important distinction is not so much whether functions are implemented as single-method objects or as a distinct function type, but <em>whether or not standard types are provided</em>.</p>
<p>There is an old joke that functional programmers say &quot;objects are just poor man's closures&quot; and OO programmers say &quot;closures are just poor man's objects&quot;. On a more serious note, there is a deep connection hidden behind those quotes, that functions are isomorphic to objects with a single method and closures are isomorphic to objects with a single method and some instance variables.</p>
<p>Which means, if your language has some sort of concept of an object with attached methods, then it doesn't make sense to add functions as a distinct entity: you already have objects with a single method.</p>
<p>Conversely, if your language already has functions, you don't necessarily need objects with attached methods, you can have objects with properties that return functions, for example.</p>
<p>So, for a language like Java, Rust, or Scala, it makes sense to implement functions as objects with a single method. There are different degrees of &quot;rigidness&quot; that you can choose:</p>
<ul>
<li>In Rust, a type that wants to act as a function must implement a specific trait with a specific method.</li>
<li>In Scala, a type that wants to act as a function must have a method named <code>apply</code> but doesn't need to implement a specific trait.</li>
<li>In Java, a type that wants to act as a function must have a single (abstract) method of arbitrary name and doesn't need to implement a specific interface.</li>
</ul>
<p>All of these are valid design choices.</p>
<p>There is, however, a big difference between Rust and Scala on the one side and Java on the other: Rust (by necessity, since the trait is part of the definition of what it means to be &quot;a function&quot;) and Scala (by choice) provide a <em>standardized interface</em> in their standard libraries. Java, until Java 8, did not.</p>
<p>Without a standardized interface in the standard library, every library author came up with their own function interfaces. Heck, even <em>within</em> the JRE, different parts of the JRE came up with different interfaces.</p>
<p>So, for example, you might have one library with a method</p>
<pre class="lang-java prettyprint-override"><code>List&lt;T&gt; filter(MyPredicate&lt;T&gt; pred)
</code></pre>
<p>with</p>
<pre class="lang-java prettyprint-override"><code>interface MyPredicate&lt;T&gt; {
  bool check(T value)
}
</code></pre>
<p>whereas another library may have</p>
<pre class="lang-java prettyprint-override"><code>void validate(Validator&lt;T&gt; v)
</code></pre>
<p>with</p>
<pre class="lang-java prettyprint-override"><code>interface Validator&lt;T&gt; {
  bool validate(T value)
}
</code></pre>
<p>This wouldn't be so much of a problem in a <em>structural type system</em> where names don't matter, but with Java's <em>nominal type system</em>, this is a problem: I cannot create a single predicate object and pass it to both methods. (Well, technically, I could implement both interfaces and both methods and have them forward to a single implementation, but you can see how that can become messy.)</p>
<p>Lambda literals are <em>structurally typed</em>, so I can write the <em>same</em> lambda literal for both, i.e. I can write</p>
<pre class="lang-java prettyprint-override"><code>list.filter(elem -&gt; doSomethingWith(elem));
value.validate(elem -&gt; doSomethingWith(elem));
</code></pre>
<p>but I can <em>not</em> write something like:</p>
<pre class="lang-java prettyprint-override"><code>SomeCommonFunctionType predicate = elem -&gt; doSomethingWith(elem);

list.filter(predicate);
value.validate(predicate);
</code></pre>
<p>Because there is no type common to both functions.</p>
<p>Java has attempted to provide common function types in the <a href="https://docs.oracle.com/en/java/javase/20/docs/api/java.base/java/util/function/package-summary.html" rel="nofollow noreferrer"><code>java.util.function</code></a> package, but by the time this package was created, there were already dozens if not hundreds distinct function types in common use.</p>
<p>In contrast, <a href="https://scala-lang.org/" rel="nofollow noreferrer">Scala</a> provides <a href="https://scala-lang.org/api/3.3.0/scala/Function1.html" rel="nofollow noreferrer">standard function interfaces</a> even though the only requirement in the language specification is that objects must have a method named <code>apply</code>. This is perfectly valid (<a href="https://scastie.scala-lang.org/JoergWMittag/YrDZ078HTIWo9rWy1IMcdQ" rel="nofollow noreferrer">runnable</a>) Scala code, even though <code>Foo</code> does not inherit from one of the function interfaces:</p>
<pre class="lang-scala prettyprint-override"><code>class Foo:
  def apply(bar: String) = bar

val foo = Foo()

foo(&quot;Hello&quot;)
</code></pre>
<p>But it would be preferable (and most Scala programmers would do this) for it to implement <code>Function1</code>:</p>
<pre class="lang-scala prettyprint-override"><code>class Foo extends (String =&gt; String):
  def apply(bar: String) = bar

val foo = Foo()

foo(&quot;Hello&quot;)
</code></pre>
<p>By the way: <code>String =&gt; String</code> is <em>not</em> a special distinct function type, it is merely syntactic sugar for <code>Function1[String, String]</code>.</p>
<p>In Scala, even <code>Array</code>s and <code>Map</code>s implement the function interfaces: <code>Array</code>s are functions from indices to elements, <code>Maps</code> are functions from keys to values.</p>
<p>Of course, this does not just apply to functions. You can make the same argument about <em>every</em> interface. For example, imagine Java didn't have the <code>Iterator</code> interface and every collection implemented iteration differently. Or if it didn't have the <code>List</code> interface and different list implementations had different method names for their operations.</p>
<p>If you take this argument to the extreme, then you come to the absurd conclusion that a standard library must provide every possible interface. That is obviously insane, so we need to find a balance.</p>
<p>However, specifically for functions, I would argue that they are <em>fundamental</em> and <em>widely-used</em> and thus deserve to be standardized.</p>

CC BY-SA 4.0
2023-06-29T06:24:03.880Z
2023-06-29T06:24:03.880Z
Jörg W Mittag
CC BY-SA 4.0
2023-06-29T13:48:35.687Z
"it doesn't make sense to add functions as a distinct entity: you already have objects with a single method" I disagree. From my experience in Kotlin, which is heavily OO, function objects are very welcome to me. A lot of clutter can be reduced, for example avoiding boxing and not having to search for the right `BiTriConsumerProducerFunction`.
Seggan
CC BY-SA 4.0
2023-06-29T15:00:48.547Z
*"Lambda literals are structurally typed"* ─ I don't think this is entirely accurate, but I see where you're coming from. Lambda literals in Java [are subject to a kind of type inference](https://docs.oracle.com/javase/specs/jls/se20/html/jls-15.html#jls-15.27.3), so that type-checking of lambda expressions somewhat resembles type-checking in a structural type system. However, Java's type system doesn't have any rules about structural equivalence for function types (or any other types), it's just that the structure is used when determining the type in the first place.
kaya3
<p>I may know what's happening in Java and Rust.</p>
<p>It may worth noting that one needs to deal with closures (say, lambda expressions with local captures). This implies that for different lambda expressions (even if they have the same input/output type), we may need a different type to store its captures. So, it is good to pose this situation to the programmer: that the type of lambda expressions is an abstract thing which may have many implementations. Java and Rust are both under this principle.</p>

CC BY-SA 4.0
2023-05-16T17:34:13.690Z
2023-05-16T17:34:13.690Z
ice1000
<p>It's worth noting that Rust's approach is actually pretty similar to Java's. In Java, a lambda expression is syntactic sugar for an anonymous class instance, implementing a specific SAM type (abstract class or interface). When writing a lambda expression, you end up with an object whose type contains a method <em>whose body</em> is the lambda you wrote. This object is a regular object that can be passed around, and this gives Java semantics akin to the &quot;first-class functions&quot; usual functional languages provide.</p>
<p>In Rust, when you write a closure, pretty much the same happens: an anonymous, internal type is created by the compiler, implementing one or more function traits (<code>FnOnce</code>, <code>FnMut</code>, <code>Fn</code>), the implementation of which contain a <code>call()</code> method <em>whose body</em> is the lambda you wrote. So, in essence, it's the same thing. Have a look at this example taken from <a href="https://doc.rust-lang.org/reference/types/closure.html" rel="noreferrer">Rust's reference</a>.</p>
<pre><code>fn f&lt;F : FnOnce() -&gt; String&gt; (g: F) {
    println!(&quot;{}&quot;, g());
}

let mut s = String::from(&quot;foo&quot;);
let t = String::from(&quot;bar&quot;);

f(|| {
    s += &amp;t;
    s
});
</code></pre>
<p>Is behaviorally equivalent to:</p>
<pre><code>struct Closure&lt;'a&gt; {
    s : String,
    t : &amp;'a String,
}

impl&lt;'a&gt; FnOnce&lt;()&gt; for Closure&lt;'a&gt; {
    type Output = String;
    fn call_once(self) -&gt; String {
        self.s += &amp;*self.t;
        self.s
    }
}

f(Closure{s: s, t: &amp;t});
</code></pre>
<p>In Rust, the lambda expression (the closure) ends up simply being an object that contains a method corresponding to the lambda, exactly like in Java. The main difference being that in Java, it's harder to optimize (since most of the hard work happens through dynamic dispatch, where in Rust dynamic dispatch is opt-in).</p>
<p>Now, as to what approach to choose for a language, it depends on what you're trying to do. Many languages get away with not supporting &quot;function objects&quot; out-of-the-box, often by instead supporting good-enough workarounds (e.g. C's function pointers). Supporting closures can be really hard when you start asking yourself value lifetime questions. If you're trying to make a functional language, you'll have to support them or you'll quickly feel limited as to what functional idioms you're able to handle.</p>

CC BY-SA 4.0
2023-05-16T17:58:25.170Z
2023-05-16T17:58:25.170Z
zdimension
CC BY-SA 4.0
2023-06-29T05:06:30.470Z
The fundamental difference though, between Java on the one side and both Haskell and Rust on the other, is that Haskell and Rust provide *standardized types* for functions, thus encouraging library authors to use those standardized types. In Java, there is no guarantee I can write a single predicate function and pass it to a collection filter method and a Swing dropdown list filter method because one of them may take a `bool java.util.function.Predicate<T>.test(T t)` and the other may take a (hypothetical) `bool SwingFilterFunction<T>.condition(T t)`.
Jörg W Mittag
CC BY-SA 4.0
2023-06-29T05:07:51.923Z
BTW, Scala is very similar to Java: any object with a method named `apply` can be called like a function (so, while Scala "fixes" the name of the method, unlike Java, just *like* Java, it does not require inheriting or implementing a specific interface), but like Rust and unlike Java, Scala *also* supplies a standard `Function` interface which is consequently used by all libraries.
Jörg W Mittag
# What are the advantages of having first-class functions versus having only anonymous class with fancy sugars?
Posted by: username_0 on 2023-05-16
In Java, there are "SAM-interfaces" which are used as "types" for lambda expressions. In Haskell, there are dedicated types for functions. In Rust, there are no types for functions, but instead there are traits for functions.

What are the differences between these approaches? For a new language, which one should be chosen?
**Tags:** rust haskell java
---
## 5 answers
### Answer by username_6 on 2023-05-16. Score: 9 | Accepted answer
It's worth noting that Rust's approach is actually pretty similar to Java's. In Java, a lambda expression is syntactic sugar for an anonymous class instance, implementing a specific SAM type (abstract class or interface). When writing a lambda expression, you end up with an object whose type contains a method whose body is the lambda you wrote. This object is a regular object that can be passed around, and this gives Java semantics akin to the "first-class functions" usual functional languages provide.
In Rust, when you write a closure, pretty much the same happens: an anonymous, internal type is created by the compiler, implementing one or more function traits (FnOnce, FnMut, Fn), the implementation of which contain a call() method whose body is the lambda you wrote. So, in essence, it's the same thing. Have a look at this example taken from Rust's reference.
fn f String> (g: F) {
    println!("{}", g());
}

let mut s = String::from("foo");
let t = String::from("bar");

f(|| {
    s += &t
    s
});

Is behaviorally equivalent to:
struct Closure<'a> {
    s : String,
    t : &'a String,
}

impl<'a> FnOnce<()> for Closure<'a> {
    type Output = String;
    fn call_once(self) -> String {
        self.s += &*self.t;
        self.s
    }
}

f(Closure{s: s, t: &t});

In Rust, the lambda expression (the closure) ends up simply being an object that contains a method corresponding to the lambda, exactly like in Java. The main difference being that in Java, it's harder to optimize (since most of the hard work happens through dynamic dispatch, where in Rust dynamic dispatch is opt-in).
Now, as to what approach to choose for a language, it depends on what you're trying to do. Many languages get away with not supporting "function objects" out-of-the-box, often by instead supporting good-enough workarounds (e.g. C's function pointers). Supporting closures can be really hard when you start asking yourself value lifetime questions. If you're trying to make a functional language, you'll have to support them or you'll quickly feel limited as to what functional idioms you're able to handle.
> **Comments:**
> **username_2** (2023-06-29): The fundamental difference though, between Java on the one side and both Haskell and Rust on the other, is that Haskell and Rust provide *standardized types* for functions, thus encouraging library authors to use those standardized types. In Java, there is no guarantee I can write a single predicate function and pass it to a collection filter method and a Swing dropdown list filter method because one of them may take a `bool java.util.function.Predicate<T>.test(T t)` and the other may take a (hypothetical) `bool SwingFilterFunction<T>.condition(T t)`.  
> **username_2** (2023-06-29): BTW, Scala is very similar to Java: any object with a method named `apply` can be called like a function (so, while Scala "fixes" the name of the method, unlike Java, just *like* Java, it does not require inheriting or implementing a specific interface), but like Rust and unlike Java, Scala *also* supplies a standard `Function` interface which is consequently used by all libraries.  
---
### Answer by username_1 on 2023-05-16. Score: 4
# First class functions are cleaner

If your closures/lambdas are SAM interfaces, in production you often end up writing a lot of duplicate interfaces for the same functions. As a Java example, one library might have a `StringPoster` while another uses `Consumer`, even though they are the same. In Kotlin, both would likely be `(String) -> Unit`, perhaps with type aliases, allowing for much greater consistency and clarity.
> **Comments:**
> **username_2** (2023-06-29): I don't think this is so much a problem of having SAM interfaces vs. first-class functions, but with the standard library providing standard interfaces. While the standard interfaces in `java.functional` were added at the same time as lambdas and streams, there is nothing inherently tying them together. They could have been provided from day 1. For example, in Scala, *every* object that has an `apply` method can be called like a function, but the majority of them still *choose* to inherit from `Function` even though it is not necessary. Conversely, library authors choose to take `Function`s …  
> **username_2** (2023-06-29): … as arguments, even though they could easily define their own types. It is basically just exploiting library authors' laziness.  
> **username_1** (2023-06-29): @JörgWMittag apologies, I dont get your argument. Can you rephrase it?  
> **username_3** (2023-07-29): IIRC this was actually an explicit decision in Java when they added lambdas. Besides integrating better into the existing language, they rationalize that complicated function types can easily lose their semantic meaning. And if you add new arguments to your StringPoster you don't have to edit the name of the type everywhere it appears.  
---
### Answer by username_4 on 2023-07-27. Score: 4
One advantage to the Java SAM approach is that while the implementation of the function-interface only needs to implement one method (and this can be made compact through lambdas), the interface itself may contain additional default methods for composing or otherwise modifying the behaviour.

For example, if a method takes a `Predicate`, then the caller just needs to pass something that takes a `T` and returns a `boolean`... but once you have an *instance* of the `Predicate`, you can do things like:

* `newPredicate = predicate.negate()`
* `newPredicate = predicate1.and(predicate2)`
* `newPredicate = predicate1.or(predicate2)`

Similarly, a `Function` only needs to take a `V` and return an `R`, but once you have one, you can do:

* `newFunction = function1.andThen(function2)`

And to be clear - it's not that these *couldn't* be done without SAM types. But it does mean that these kinds of operation can be tailored to the needs of a particular interface... e.g. the predicate case provides operations which make sense for a predicate, but not necessarily for an arbitrary function that returned a boolean.
> **Comments:**
> **username_5** (2023-07-27): Another neat thing about such functional interfaces is, if it makes sense to do so, you can write a proper class instead of just a lambda expression, and provide specialised implementations of `negate`, `and` and `or` which might be more performant than the default implementations.  
> **username_4** (2023-07-31): Yes... one util function I use regularly wraps a `Function<V,R>` and a `Map<V,R>`, invisibly caching the results of the former using the latter. Very handy for short-lived caching, e.g. avoiding unnecessary database hits while processing a list that may contain a lot of repeated references.  
---
### Answer by username_2 on 2023-06-29. Score: 2
I believe the important distinction is not so much whether functions are implemented as single-method objects or as a distinct function type, but whether or not standard types are provided.
There is an old joke that functional programmers say "objects are just poor man's closures" and OO programmers say "closures are just poor man's objects". On a more serious note, there is a deep connection hidden behind those quotes, that functions are isomorphic to objects with a single method and closures are isomorphic to objects with a single method and some instance variables.
Which means, if your language has some sort of concept of an object with attached methods, then it doesn't make sense to add functions as a distinct entity: you already have objects with a single method.
Conversely, if your language already has functions, you don't necessarily need objects with attached methods, you can have objects with properties that return functions, for example.
So, for a language like Java, Rust, or Scala, it makes sense to implement functions as objects with a single method. There are different degrees of "rigidness" that you can choose:

In Rust, a type that wants to act as a function must implement a specific trait with a specific method.
In Scala, a type that wants to act as a function must have a method named apply but doesn't need to implement a specific trait.
In Java, a type that wants to act as a function must have a single (abstract) method of arbitrary name and doesn't need to implement a specific interface.

All of these are valid design choices.
There is, however, a big difference between Rust and Scala on the one side and Java on the other: Rust (by necessity, since the trait is part of the definition of what it means to be "a function") and Scala (by choice) provide a standardized interface in their standard libraries. Java, until Java 8, did not.
Without a standardized interface in the standard library, every library author came up with their own function interfaces. Heck, even within the JRE, different parts of the JRE came up with different interfaces.
So, for example, you might have one library with a method
List filter(MyPredicate pred)

with
interface MyPredicate {
  bool check(T value)
}

whereas another library may have
void validate(Validator v)

with
interface Validator {
  bool validate(T value)
}

This wouldn't be so much of a problem in a structural type system where names don't matter, but with Java's nominal type system, this is a problem: I cannot create a single predicate object and pass it to both methods. (Well, technically, I could implement both interfaces and both methods and have them forward to a single implementation, but you can see how that can become messy.)
Lambda literals are structurally typed, so I can write the same lambda literal for both, i.e. I can write
list.filter(elem -> doSomethingWith(elem));
value.validate(elem -> doSomethingWith(elem));

but I can not write something like:
SomeCommonFunctionType predicate = elem -> doSomethingWith(elem);

list.filter(predicate);
value.validate(predicate);

Because there is no type common to both functions.
Java has attempted to provide common function types in the java.util.function package, but by the time this package was created, there were already dozens if not hundreds distinct function types in common use.
In contrast, Scala provides standard function interfaces even though the only requirement in the language specification is that objects must have a method named apply. This is perfectly valid (runnable) Scala code, even though Foo does not inherit from one of the function interfaces:
class Foo:
  def apply(bar: String) = bar

val foo = Foo()

foo("Hello")

But it would be preferable (and most Scala programmers would do this) for it to implement Function1:
class Foo extends (String => String):
  def apply(bar: String) = bar

val foo = Foo()

foo("Hello")

By the way: String => String is not a special distinct function type, it is merely syntactic sugar for Function1[String, String].
In Scala, even Arrays and Maps implement the function interfaces: Arrays are functions from indices to elements, Maps are functions from keys to values.
Of course, this does not just apply to functions. You can make the same argument about every interface. For example, imagine Java didn't have the Iterator interface and every collection implemented iteration differently. Or if it didn't have the List interface and different list implementations had different method names for their operations.
If you take this argument to the extreme, then you come to the absurd conclusion that a standard library must provide every possible interface. That is obviously insane, so we need to find a balance.
However, specifically for functions, I would argue that they are fundamental and widely-used and thus deserve to be standardized.
> **Comments:**
> **username_1** (2023-06-29): "it doesn't make sense to add functions as a distinct entity: you already have objects with a single method" I disagree. From my experience in Kotlin, which is heavily OO, function objects are very welcome to me. A lot of clutter can be reduced, for example avoiding boxing and not having to search for the right `BiTriConsumerProducerFunction`.  
> **username_5** (2023-06-29): *"Lambda literals are structurally typed"* ─ I don't think this is entirely accurate, but I see where you're coming from. Lambda literals in Java [are subject to a kind of type inference](https://docs.oracle.com/javase/specs/jls/se20/html/jls-15.html#jls-15.27.3), so that type-checking of lambda expressions somewhat resembles type-checking in a structural type system. However, Java's type system doesn't have any rules about structural equivalence for function types (or any other types), it's just that the structure is used when determining the type in the first place.  
---
### Answer by username_0 on 2023-05-16. Score: 2
I may know what's happening in Java and Rust.

It may worth noting that one needs to deal with closures (say, lambda expressions with local captures). This implies that for different lambda expressions (even if they have the same input/output type), we may need a different type to store its captures. So, it is good to pose this situation to the programmer: that the type of lambda expressions is an abstract thing which may have many implementations. Java and Rust are both under this principle.
---
