Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Assignment ?][11/13 Lecture Question] "Is it possible to define a generic closure in Rust?" #424

Closed
Jeong-jin-Han opened this issue Nov 13, 2024 · 3 comments
Assignees
Labels
question Further information is requested

Comments

@Jeong-jin-Han
Copy link

Related Issue

https://github.com/nrc/r4cppp/blob/master/closures.md

Googling Result

https://users.rust-lang.org/t/use-generics-in-closure/86679

ChatGPT Result

https://chatgpt.com/c/

Your question here

I tried defining a generic closure in Rust like this:

let example_closure<T> = |x: T| x;

However, this produces a compiler error: expected one of ':' , ';', '=', '@', or '|'. I understand that closures in Rust infer types based on their first use, but is there a way to explicitly make a closure generic without wrapping it in a function or struct? If not, could you explain why this limitation exists?

@Jeong-jin-Han Jeong-jin-Han added the question Further information is requested label Nov 13, 2024
@Jeong-jin-Han Jeong-jin-Han changed the title [Assignment ?][11/13 Lecture Question] "Is it possible to define a generic closure in Rust?" - [Answer] Maybe Yes?? [Assignment ?][11/13 Lecture Question] "Is it possible to define a generic closure in Rust?" - [Answer] Maybe No?? Nov 13, 2024
@Jeong-jin-Han Jeong-jin-Han changed the title [Assignment ?][11/13 Lecture Question] "Is it possible to define a generic closure in Rust?" - [Answer] Maybe No?? [Assignment ?][11/13 Lecture Question] "Is it possible to define a generic closure in Rust?" Nov 13, 2024
@Lee-Janggun
Copy link
Member

There isn't. I'm not sure why it isn't supported, but my guess is that closures are typically single-use functions, so there is no real point on making it generic in the most case.
Also, generic code needs to be monomorphized at compile time, and it would be very difficult to account to do that for arbitrary let statements.

@Jeong-jin-Han
Copy link
Author

Thank you!!

@Jaewookim08
Copy link
Collaborator

I came across an RFC about adding generic closures, but it seems like it's been postponed forever—just like so many other cool features proposed for Rust...

rust-lang/rfcs#1650 (comment):

I suggest we postpone this RFC until we're a good bit further along with the impending trait system revamp, which I think should make this kind of thing much easier to implement and reason about.

Nonetheless, the syntax you've tried for (let example_closure<T> = |x: T| x;) would never work. Below is a simple description on how closures are implemented in Rust and why the syntax won't work, so please have a look if you're interested.


Closures are structs.

Unlike normal Rust functions, which we reference by primitive 'function pointer' types (fn), each closure has its own type, auto-generated by the compiler. For example, the following code:

let b = 3u32;
let a = |x: u32| x + b;

is transformed by the compiler to the following:

struct __some_anonymous_type {
    b : u32,  // all captured values become a member of the closure struct.
}
impl Fn<u32> for __some_anonymous_type { // compiler auto-generates `Fn` implementation.
    fn call(&self, x: u32) -> Self::Output {
        x + self.b
    }
}
// `FnMut` and `FnOnce` are also implemented similarly.

let b = 3u32;
let a = __some_anonymous_type{ b };

Then we can 'call' this value 'a' of an anonymous struct type, just as we call normal functions.

assert_eq!(a(7), 10);

This 'call' on a struct is allowed since a function call (f(arg0, arg1, ...)) uses one of the traits: Fn, FnMut, or FnOnce. The Rust compiler determines which trait to use for each function call based on context. For more information about the differences between these traits, refer to the Rust book.

Now it is clear why your generic closure code doesn't work.

let example_closure<T> = |x: T| x;

would be interpreted as:

let example_closure<T> = __some_closure<T>{};

This would require generic variables, which don't exist in Rust for obvious reasons.

Generic closures in other languages

C++'s template lambda

C++ supports lambdas (closures) to use templates, a concept similar to generics in Rust.

auto a = []<typename T>(T x) { return x; };

Similar to Rust, the compiler will translate this into a struct instantiation.

struct __anonymous{
    template<T> T operator ()(T x) const { return x; }
}
auto a = __anonymous{};

Note that C++ doesn't require the template type T to have trait bounds, as C++ uses compile-time duck typing, unlike Rust.

If it walks like a duck and it quacks like a duck, then it must be a duck.

Dependent types

A few programming languages such as Coq or Idris utilize first-class types, meaning that types can be given to and returned from functions just like other values. This concept is also called dependent types—a type can depend on a value. Using this, we can mimic generic functions.

Definition a (T : Type) (x : T) := x.

Note that the return type of a, T, depends on the first argument value T: Type. (x is a value of type T, and T is a value of type Type. I know that sounds weird...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants