Is there any way to explicitly write the type of a closure? - closures

I started reading the Rust guide on closures. From the guide:
That is because in Rust each closure has its own unique type. So, not only do closures with different signatures have different types, but different closures with the same signature have different types, as well.
Is there a way to explicitly write the type signature of a closure? Is there any compiler flag that expands the type of inferred closure?

No. The real type of a closure is only known to the compiler, and it's not actually that useful to be able to know the concrete type of a given closure. You can specify certain "shapes" that a closure must fit, however:
fn call_it<F>(f: F)
where
F: Fn(u8) -> u8, // <--- HERE
{
println!("The result is {}", f(42))
}
fn main() {
call_it(|a| a + 1);
}
In this case, we say that call_it accepts any type that implements the trait Fn with one argument of type u8 and a return type of u8. Many closures and free functions can implement that trait however.
As of Rust 1.26.0, you can also use the impl Trait syntax to accept or return a closure (or any other trait):
fn make_it() -> impl Fn(u8) -> u8 {
|a| a + 1
}
fn call_it(f: impl Fn(u8) -> u8) {
println!("The result is {}", f(42))
}
fn main() {
call_it(make_it());
}

Quoting the reference, "A closure expression produces a closure value with a unique, anonymous type that cannot be written out".
However, under conditions defined by RFC1558, a closure can be coerced to a function pointer.
let trim_lines: fn((usize, &str)) -> (usize, &str) = |(i, line)| (i, line.trim());
Function pointers can be used in .map(), .filter(), etc just like a regular function. Types will be different but the Iterator trait will be present on the returned values.

Related

Cannot infer type for `B` for filter_map().sum()

The code below reads numbers, sums them, then prints the sum. I've tried few annotations, but it didn't work. I must be missing something. How could I make it work?
use std::io;
use std::io::Read;
fn main() {
let mut buff = String::new();
io::stdin().read_to_string(&mut buff).expect("read_to_string error");
let v: i32 = buff
.split_whitespace()
.filter_map(|w| w.parse().ok())
.sum();
println!("{:?}", v);
}
Error message from compiler:
type annotations needed
--> src\main.rs:9:10
|
9 | .filter_map(|w| w.parse().ok())
| ^^^^^^^^^^ cannot infer type for `B`
Let's look up the signature of filter_map to see, what the complain is about:
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> where F: FnMut(Self::Item) -> Option<B>,
Okay, so Option<B> is the result, which means he cannot infer what w.parse().ok() will be.
Let's try to give him a hint
.filter_map(|w| w.parse::<i32>().ok())
Let's compile an see.... Hurray!
So, lesson learned: Look up the signature and try to figure out, which part the compiler cannot infer and try to specify it.
The quick fix is to say which type you are parsing into:
let v: i32 = buff
.split_whitespace()
.filter_map(|w| w.parse::<i32>().ok())
.sum();
The reason is that filter_map has a type variable B, which would need to be inferred from the closure that you pass to it (the closure returns Option<B>). However, parse() also has a type variable for the type you are parsing into, which also can often be inferred. But here the type-checker would have to infer each of these types from each other, which obviously can't be done. To break the cycle, you have to tell it somewhere what the concrete type is.
You also could have fixed it by annotating filter_map. It's not as nice because filter_map has two type parameters, but you can still let the second one be inferred by using an _:
let v: i32 = buff
.split_whitespace()
.filter_map::<i32, _>(|w| w.parse().ok())
.sum();

Return something that's allocated on the stack

I have the following simplified code, where a struct A contains a certain attribute. I'd like to create new instances of A from an existing version of that attribute, but how do I make the lifetime of the attribute's new value last past the function call?
pub struct A<'a> {
some_attr: &'a str,
}
impl<'a> A<'a> {
fn combine(orig: &'a str) -> A<'a> {
let attr = &*(orig.to_string() + "suffix");
A { some_attr: attr }
}
}
fn main() {
println!("{}", A::combine("blah").some_attr);
}
The above code produces
error[E0597]: borrowed value does not live long enough
--> src/main.rs:7:22
|
7 | let attr = &*(orig.to_string() + "suffix");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not live long enough
8 | A { some_attr: attr }
9 | }
| - temporary value only lives until here
|
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 5:1...
--> src/main.rs:5:1
|
5 | / impl<'a> A<'a> {
6 | | fn combine(orig: &'a str) -> A<'a> {
7 | | let attr = &*(orig.to_string() + "suffix");
8 | | A { some_attr: attr }
9 | | }
10| | }
| |_^
This question most certainly was answered before, but I'm not closing it as a duplicate because the code here is somewhat different and I think it is important.
Note how you defined your function:
fn combine(orig: &'a str) -> A<'a>
It says that it will return a value of type A whose insides live exactly as long as the provided string. However, the body of the function violates this declaration:
let attr = &*(orig.to_string() + "suffix");
A {
some_attr: attr
}
Here you construct a new String obtained from orig, take a slice of it and try to return it inside A. However, the lifetime of the implicit variable created for orig.to_string() + "suffix" is strictly smaller than the lifetime of the input parameter. Therefore, your program is rejected.
Another, more practical way to look at this is consider that the string created by to_string() and concatenation has to live somewhere. However, you only return a borrowed slice of it. Thus when the function exits, the string is destroyed, and the returned slice becomes invalid. This is exactly the situation which Rust prevents.
To overcome this you can either store a String inside A:
pub struct A {
some_attr: String
}
or you can use std::borrow::Cow to store either a slice or an owned string:
pub struct A<'a> {
some_attr: Cow<'a, str>
}
In the last case your function could look like this:
fn combine(orig: &str) -> A<'static> {
let attr = orig.to_owned() + "suffix";
A {
some_attr: attr.into()
}
}
Note that because you construct the string inside the function, it is represented as an owned variant of Cow and so you can use 'static lifetime parameter for the resulting value. Tying it to orig is also possible but there is no reason to do so.
With Cow it is also possible to create values of A directly out of slices without allocations:
fn new(orig: &str) -> A {
A { some_attr: orig.into() }
}
Here the lifetime parameter of A will be tied (through lifetime elision) to the lifetime of the input string slice. In this case the borrowed variant of Cow is used, and no allocation is done.
Also note that it is better to use to_owned() or into() to convert string slices to Strings because these methods do not require formatting code to run and so they are more efficient.
how can you return an A of lifetime 'static when you're creating it on the fly? Not sure what "owned variant of Cow" means and why that makes 'static possible.
Here is the definition of Cow:
pub enum Cow<'a, B> where B: 'a + ToOwned + ?Sized {
Borrowed(&'a B),
Owned(B::Owned),
}
It looks complex but it is in fact simple. An instance of Cow may either contain a reference to some type B or an owned value which could be derived from B via the ToOwned trait. Because str implements ToOwned where Owned associated type equals to String (written as ToOwned<Owned = String>, when this enum is specialized for str, it looks like this:
pub enum Cow<'a, str> {
Borrowed(&'a str),
Owned(String)
}
Therefore, Cow<str> may represent either a string slice or an owned string - and while Cow does indeed provide methods for clone-on-write functionality, it is just as often used to hold a value which can be either borrowed or owned in order to avoid extra allocations. Because Cow<'a, B> implements Deref<Target = B>, you can get &B from Cow<'a, B> with simple reborrowing: if x is Cow<str>, then &*x is &str, regardless of what is contained inside of x - naturally, you can get a slice out of both variants of Cow.
You can see that the Cow::Owned variant does not contain any references inside it, only String. Therefore, when a value of Cow is created using Owned variant, you can choose any lifetime you want (remember, lifetime parameters are much like generic type parameters; in particular, it is the caller who gets to choose them) - there are no restrictions on it. So it makes sense to choose 'static as the greatest lifetime possible.
Does orig.to_owned remove ownership from whoever's calling this function? That sounds like it would be inconvenient.
The to_owned() method belongs to ToOwned trait:
pub trait ToOwned {
type Owned: Borrow<Self>;
fn to_owned(&self) -> Self::Owned;
}
This trait is implemented by str with Owned equal to String. to_owned() method returns an owned variant of whatever value it is called on. In this particular case, it creates a String out of &str, effectively copying contents of the string slice into a new allocation. Therefore no, to_owned() does not imply ownership transfer, it's more like it implies a "smart" clone.
As far as I can tell String implements Into<Vec<u8>> but not str, so how can we call into() in the 2nd example?
The Into trait is very versatile and it is implemented for lots of types in the standard library. Into is usually implemented through the From trait: if T: From<U>, then U: Into<T>. There are two important implementations of From in the standard library:
impl<'a> From<&'a str> for Cow<'a, str>
impl<'a> From<String> for Cow<'a, str>
These implementations are very simple - they just return Cow::Borrowed(value) if value is &str and Cow::Owned(value) if value is String.
This means that &'a str and String implement Into<Cow<'a, str>>, and so they can be converted to Cow with into() method. That's exactly what happens in my example - I'm using into() to convert String or &str to Cow<str>. Without this explicit conversion you will get an error about mismatched types.

How do I create & use a list of callback functions?

In Rust, I'm trying to create a list of callbacks functions to invoke later:
use std::vec::Vec;
fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
v.push(Box::new(f));
}
fn call_b() {
println!("Call b.");
}
#[test]
fn it_works() {
let calls: Vec<Box<FnMut() -> ()>> = Vec::new();
add_to_vec(&calls, || { println!("Call a."); });
add_to_vec(&calls, call_b);
for c in calls.drain() {
c();
}
}
I'm mostly following the advice here on how to store a closure, however, I'm still seeing some errors:
src/lib.rs:6:12: 6:23 error: the parameter type `T` may not live long enough [E0311]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
src/lib.rs:6:23: 6:23 help: consider adding an explicit lifetime bound for `T`
src/lib.rs:5:68: 7:2 note: the parameter type `T` must be valid for the anonymous lifetime #1 defined on the block at 5:67...
src/lib.rs:5 fn add_to_vec<T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: T) {
src/lib.rs:6 v.push(Box::new(f));
src/lib.rs:7 }
src/lib.rs:6:12: 6:23 note: ...so that the type `T` will meet its required lifetime bounds
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
I've tried changing the function signature to:
fn add_to_vec<'a, T: FnMut() -> ()>(v: &Vec<Box<FnMut() -> ()>>, f: &'a T) {
… but this gets me:
src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
error: aborting due to previous error
src/lib.rs:6:12: 6:23 error: the trait `core::ops::Fn<()>` is not implemented for the type `&T` [E0277]
src/lib.rs:6 v.push(Box::new(f));
^~~~~~~~~~~
src/lib.rs:18:24: 18:51 error: mismatched types:
expected `&_`,
found `[closure src/lib.rs:18:24: 18:51]`
(expected &-ptr,
found closure) [E0308]
src/lib.rs:18 add_to_vec(&calls, || { println!("Call a."); });
^~~~~~~~~~~~~~~~~~~~~~~~~~~
(The last error I can correct by adding a &; while I think this is something I should need, because add_to_vec is going to end up owning the closure, and thus needs to borrow it, I'm not entirely sure.)
There are a few problems with your code. Here’s a fully fixed version to begin with:
use std::vec::Vec;
fn add_to_vec<'a, T: FnMut() + 'a>(v: &mut Vec<Box<FnMut() + 'a>>, f: T) {
v.push(Box::new(f));
}
fn call_b() {
println!("Call b.");
}
#[test]
fn it_works() {
let mut calls: Vec<Box<FnMut()>> = Vec::new();
add_to_vec(&mut calls, || { println!("Call a."); });
add_to_vec(&mut calls, call_b);
for mut c in calls.drain() {
c();
}
}
The lifetime issue is that the boxed function objects must have a common base lifetime; if you just write the generic constraint T: FnMut(), it is assumed to only need to live as long as the function call and not any longer. Therefore two things need to be added to it all: the generic parameter T must be constrained to a specified lifetime, and in order to store it inside the vector, the trait object type must similarly be constrained, as Box<FnMut() + 'a>. That way they both match up and memory safety is ensured and so the compiler lets it through. The -> () part of FnMut() -> () is superfluous, by the way.
The remaining fixes that need to be made are the insertion of a few mut; in order to push to the vector, you naturally need a mutable reference, hence the & to &mut changes, and in order to take mutable references to calls and c the bindings must be made mut.

Rust: using traits/typeclasses to implement a generic numeric function

I have a function which works to make a linked list of integers:
enum List<T> { Cons(T, ~List<T>), End }
fn range(start: int, end: int) -> ~List<int> {
if start >= end { ~End }
else { ~Cons(start, range(start+1, end)) }
}
However, I want to make a range of any numeric type, including uints, doubles and the like. But this, for example, doesn't work:
fn range<T: ord>(start: T, end: T) -> ~List<T> {
if start >= end { ~End }
else { ~Cons(start, range(start+1, end)) }
}
which produces:
> rustc list.rs
list.rs:3:12: 3:15 error: use of undeclared type name `ord`
list.rs:3 fn range<T: ord>(start: T, end: T) -> ~List<T> {
^~~
error: aborting due to previous error
How can I make a generic function in rust which restricts itself to be callable by "numeric" types? Without having to specifically write the interface myself? I had assumed that there were a number of standard-library traits (such as those listed in section 6.2.1.1 of the manual like eq, ord, etc, though now I'm wondering if those are proper "traits" at all) that I could use when declaring generic functions?
The traits are usually uppercase. In this case it is Ord. See if that helps.
In the current master, there is a trait named 'Num' which serves as a general trait for all numeric types. Work has been done recently to unify many of the common math functions to work on this trait rather than u8, f32, etc , specifically.
See https://github.com/mozilla/rust/blob/master/src/libstd/num/num.rs#L26 for the aforementioned Num trait.
Hope this helps!

How does F# compile functions that can take multiple different parameter types into IL?

I know virtually nothing about F#. I don’t even know the syntax, so I can’t give examples.
It was mentioned in a comment thread that F# can declare functions that can take parameters of multiple possible types, for example a string or an integer. This would be similar to method overloads in C#:
public void Method(string str) { /* ... */ }
public void Method(int integer) { /* ... */ }
However, in CIL you cannot declare a delegate of this form. Each delegate must have a single, specific list of parameter types. Since functions in F# are first-class citizens, however, it would seem that you should be able to pass such a function around, and the only way to compile that into CIL is to use delegates.
So how does F# compile this into CIL?
This question is a little ambiguous, so I'll just ramble about what's true of F#.
In F#, methods can be overloaded, just like C#. Methods are always accessed by a qualified name of the form someObj.MethodName or someType.MethodName. There must be context which can statically resolve the overload at compile-time, just as in C#. Examples:
type T() =
member this.M(x:int) = ()
member this.M(x:string) = ()
let t = new T()
// these are all ok, just like C#
t.M(3)
t.M("foo")
let f : int -> unit = t.M
let g : string-> unit = t.M
// this fails, just like C#
let h = t.M // A unique overload for method 'M' could not be determined
// based on type information prior to this program point.
In F#, let-bound function values cannot be overloaded. So:
let foo(x:int) = ()
let foo(x:string) = () // Duplicate definition of value 'foo'
This means you can never have an "unqualified" identifier foo that has overloaded meaning. Each such name has a single unambiguous type.
Finally, the crazy case which is probably the one that prompts the question. F# can define inline functions which have "static member constraints" which can be bound to e.g. "all types T that have a member property named Bar" or whatnot. This kind of genericity cannot be encoded into CIL. Which is why the functions that leverage this feature must be inline, so that at each call site, the code specific-to-the-type-used-at-that-callsite is generated inline.
let inline crazy(x) = x.Qux(3) // elided: type syntax to constrain x to
// require a Qux member that can take an int
// suppose unrelated types U and V have such a Qux method
let u = new U()
crazy(u) // is expanded here into "u.Qux(3)" and then compiled
let v = new V()
crazy(v) // is expanded here into "v.Qux(3)" and then compiled
So this stuff is all handled by the compiler, and by the time we need to generate code, once again, we've statically resolved which specific type we're using at this callsite. The "type" of crazy is not a type that can be expressed in CIL, the F# type system just checks each callsite to ensure the necessary conditions are met and inlines the code into that callsite, a lot like how C++ templates work.
(The main purpose/justification for the crazy stuff is for overloaded math operators. Without the inline feature, the + operator, for instance, being a let-bound function type, could either "only work on ints" or "only work on floats" or whatnot. Some ML flavors (F# is a relative of OCaml) do exactly that, where e.g. the + operator only works on ints, and a separate operator, usually named +., works on floats. Whereas in F#, + is an inline function defined in the F# library that works on any type with a + operator member or any of the primitive numeric types. Inlining can also have some potential run-time performance benefits, which is also appealing for some math-y/computational domains.)
When you're writing C# and you need a function that can take multiple different parameter sets, you just create method overloads:
string f(int x)
{
return "int " + x;
}
string f(string x)
{
return "string " + x;
}
void callF()
{
Console.WriteLine(f(12));
Console.WriteLine(f("12"));
}
// there's no way to write a function like this:
void call(Func<int|string, string> func)
{
Console.WriteLine(func(12));
Console.WriteLine(func("12"));
}
The callF function is trivial, but my made-up syntax for the call function doesn't work.
When you're writing F# and you need a function that can take multiple different parameter sets, you create a discriminated union that can contain all the different parameter sets and you make a single function that takes that union:
type Either = Int of int
| String of string
let f = function Int x -> "int " + string x
| String x -> "string " + x
let callF =
printfn "%s" (f (Int 12))
printfn "%s" (f (String "12"))
let call func =
printfn "%s" (func (Int 12))
printfn "%s" (func (String "12"))
Being a single function, f can be used like any other value, so in F# we can write callF and call f, and both do the same thing.
So how does F# implement the Either type I created above? Essentially like this:
public abstract class Either
{
public class Int : Test.Either
{
internal readonly int item;
internal Int(int item);
public int Item { get; }
}
public class String : Test.Either
{
internal readonly string item;
internal String(string item);
public string Item { get; }
}
}
The signature of the call function is:
public static void call(FSharpFunc<Either, string> f);
And f looks something like this:
public static string f(Either _arg1)
{
if (_arg1 is Either.Int)
return "int " + ((Either.Int)_arg1).Item;
return "string " + ((Either.String)_arg1).Item;
}
Of course you could implement the same Either type in C# (duh!), but it's not idiomatic, which is why it wasn't the obvious answer to the previous question.
Assuming I understand the question, in F# you can define expressions which depend on the availability of members with particular signatures. For instance
let inline f x a = (^t : (member Method : ^a -> unit)(x,a))
This defines a function f which takes a value x of type ^t and a value a of type ^a where ^t has a method Method taking an ^a to unit (void in C#), and which calls that method. Because this function is defined as inline, the definition is inlined at the point of use, which is the only reason that it can be given such a type. Thus, although you can pass f as a first class function, you can only do so when the types ^t and ^a are statically known so that the method call can be statically resolved and inserted in place (and this is why the type parameters have the funny ^ sigil instead of the normal ' sigil).
Here's an example of passing f as a first-class function:
type T() =
member x.Method(i) = printfn "Method called with int: %i" i
List.iter (f (new T())) [1; 2; 3]
This runs the method Method against the three values in the list. Because f is inlined, this is basically equivalent to
List.iter ((fun (x:T) a -> x.Method(a)) (new T())) [1; 2; 3]
EDIT
Given the context that seems to have led to this question (C# - How can I “overload” a delegate?), I appear not to have addressed your real question at all. Instead, what Gabe appears to be talking about is the ease with which one can define and use discriminated unions. So the question posed on that other thread might be answered like this using F#:
type FunctionType =
| NoArgument of (unit -> unit)
| ArrayArgument of (obj[] -> unit)
let doNothing (arr:obj[]) = ()
let doSomething () = printfn "'doSomething' was called"
let mutable someFunction = ArrayArgument doNothing
someFunction <- NoArgument doSomething
//now call someFunction, regardless of what type of argument it's supposed to take
match someFunction with
| NoArgument f -> f()
| ArrayArgument f -> f [| |] // pass in empty array
At a low level, there's no CIL magic going on here; it's just that NoArgument and ArrayArgument are subclasses of FunctionType which are easy to construct and to deconstruct via pattern matching. The branches of the pattern matching expression are morally equivalent to a type test followed by property accesses, but the compiler makes sure that the cases have 100% coverage and don't overlap. You could encode the exact same operations in C# without any problem, but it would be much more verbose and the compiler wouldn't help you out with exhaustiveness checking, etc.
Also, there is nothing here which is particular to functions; F# discriminated unions make it easy to define types which have a fixed number of named alternatives, each one of which can have data of whatever type you'd like.
I'm not quite sure that understand your question correctly... F# compiler uses FSharpFunc type to represent functions. Usually in F# code you don't deal with this type directly, using fancy syntactic representation instead, but if you expose any members that returns or accepts function and use them from another language, line C# - you will see it.
So instead of using delegates - F# utilizes its special type with concrete or generic parameters.
If your question was about things like add something-i-don't-know-what-exactly-but-it-has-addition-operator then you need to use inline keyword and compiler will emit function body in the call site. #kvb's answer was describing exactly this case.

Resources