How to deref tuple of references - rust

use std::collections::BTreeMap;
fn main() {
let mut m = BTreeMap::new();
m.insert(1, 1);
let (a, b) = *m.iter().next().unwrap();
}
I am trying to get de-refed version of (key, value) pair returned from the btreemap. But using dereference operator directly upon the returned (& ,&) pair is not working.
Is there a way to do this so that the type of a, b are just u64, not &u64?

A & before a variable in a pattern (used by let) will dereference it.
let (&a, &b) = m.iter().next().unwrap();

Related

Covariant Types

According the Rustonomicon, &mut T is invariant over T. How can the following code compile when &mut (str, str) is not a subtype of &mut (T, T)?
fn swap<T: Copy>(pair: &mut (T, T)) {
let temp = pair.0;
pair.0 = pair.1;
pair.1 = temp;
}
fn main() {
let mut pair = ("left", "right");
swap(&mut pair);
println!("{:?}", pair);
}
The relevant chapter is here
The Rustonomicon implies that you can call f: (T) -> U on f(V) only if V is a subtype of T. (4th code block, the example is evil_feeder(pet: &mut Animal) being called with &mut Cat). How can the above example compile if it's not a subtype?
Variance is primarily about type coercion and only secondarily about generics.
See also https://ehsanmkermani.com/2019/03/16/variance-in-rust-an-intuitive-explanation/, https://doc.rust-lang.org/reference/subtyping.html, and https://doc.rust-lang.org/reference/type-coercions.html#coercion-types.
It can compile because you are not using a &mut (str, str). What you have is an &mut (&'static str, &'static str). This is because string literals are references to the read-only memory where the actual string was stored in the executable.
It can fulfill the requirement of the function because even though str does not implement Copy, all immutable references implement Copy.

Can I simplify tuple expression that uses a double reference?

I have an expression that creates variables that are double references, only to have to dereference the variable to use it in a call. I suspect there is a simpler syntax and way to call my function.
I have two types A and B, neither movable, but both cloneable. I am calling a function with a Vec of tuples of A and B and need to index the Vec to get out the tuple, destructure the values from the tuple into local variables, and use one value immutably but the other mutably in another function call.
pub fn my_func(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize; // Would be a loop index normally.
let (a, b) = &mut v[i]; // This makes b a double reference.
x.do_something(*b); // This expects &mut B as parameter.
}
How can I change the signature to my_func, the indexing of v and the destructuring into a and b in a consistent way to simplify things? Can I get away with fewer ampersands and muts and derefs? Note that I do not need a to be mutable, just b.
Ignoring &mut C since it is required, if you count one point for each ampersand &, one point for each mut, and one point for each deref *, then you get 8 points. A solution that scores fewer "points" is a winner.
I don't think there is any way to simplify the function's signature. You could replace Vec<T> with [T], provided you don't need to push or pop elements from the vector, but this change doesn't affect the "score" per your definition.
Both a and b turn into double references because of match ergonomics.
The pattern on the left side of the let doesn't have exactly the same "shape" as the expression on the right, so the compiler "fixes" it for you. The type of the expression is &mut (&A, &mut B). The pattern doesn't match the outer &mut, so the compiler pushes it inside the tuple, giving (&mut &A, &mut &mut B). Now the shapes match: the outer type is a 2-tuple, so a is &mut &A and b is &mut &mut B.
I've come up with a few variations on your function:
pub struct A;
pub struct B;
pub struct C;
impl C {
fn do_something(&mut self, b: &mut B) {}
}
pub fn my_func_v1(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize;
let (a, b) = &mut v[i];
x.do_something(b);
}
pub fn my_func_v2(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize;
let &mut (a, &mut ref mut b) = &mut v[i];
x.do_something(b);
}
pub fn my_func_v2a(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize;
let (a, &mut ref mut b) = v[i];
x.do_something(b);
}
pub fn my_func_v3(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize;
let (a, b) = &mut v[i];
let (a, b) = (*a, &mut **b);
// Or:
//let a = *a;
//let b = &mut **b;
x.do_something(b);
}
pub fn my_func_v4(v: &mut Vec<(&A, &mut B)>, x: &mut C) {
let i = 0_usize;
let e = &mut v[i];
let (a, b) = (e.0, &mut *e.1);
// Or:
//let a = e.0;
//let b = &mut *e.1;
x.do_something(b);
}
v1 is identical, except I wrote b instead of *b. The compiler sees an expression of type &mut &mut B and a parameter of type &mut B, and will transparently dereference the outer reference. This might not work if the parameter type is generic (here, it's the nongeneric &mut B).
v2 is the "direct" way to avoid making a and b double references. As you can see, it's not very pretty. First, I added &mut in front of the tuple, in order to match the type of the expression on the right, to prevent match ergonomics from kicking in. Next, we can't just write b because the compiler interprets this pattern as a move/copy, but we can't move out of a mutable reference and &mut T is not Copy. &mut ref mut b is the pattern version of a reborrow.
v2a is like v2, but with the &mut removed on both sides (thanks loganfsmyth for the reminder!). v[i] is of type (&A, &mut B), so it cannot be moved, but it's an lvalue, so if we re-reference parts of it that cannot be moved/copied, then the whole thing won't be moved at all.
Remember that in patterns, &mut deconstructs a reference, while ref mut constructs a reference. Now, &mut ref mut might seem like a noop, but it's not. A double mutable reference &mut &mut T actually has two distinct lifetimes; let's name them 'a for the inner lifetime and 'b for the outer lifetime, giving &'b mut &'a mut T ('b is shorter than 'a). When you dereference such a value (either with the * operator or with a &mut pattern), the output is &'b mut T, not &'a mut T. If it were &'a mut T, then you could end up with more than one mutable reference to the same memory location. b yields a &'a mut T, while &mut ref mut b yields a &'b mut T.
v3 uses the dereferencing operator instead of &mut patterns, which is hopefully easier to understand. We need to explicitly reborrow (&mut **b), unfortunately; *b is interpreted as a move out of a mutable reference, again.
When b is &mut &mut B and we pass either b or *b to do_something, neither of these two are actually "correct". The correct expression is &mut **b. However, the compiler automatically references and dereferences arguments (including the receiver) in function/method calls, but not in other contexts (such as the initializer for a local variable).
v4 saves a couple * by relying on the auto-deref from using the . operator.
One option is to explicitly declare the b binding to be a reference into v[i] directly. This can be done with
let (a, ref mut b) = v[i];
x.do_something(b);
For simplifying the signature, you're pretty limited, but one place to start would be
pub fn my_func(v: &mut [(&A, &mut B)], x: &mut C) {
assuming your function doesn't actually try to add/remove items in the vector.

return closures but cannot infer type

When learning rust closures,I try Like Java return "A Function"
fn equal_5<T>() -> T
where T: Fn(u32) -> bool {
let x:u32 = 5;
|z| z == x
}
But when i use it
let compare = equal_5();
println!("eq {}", compare(6));
Build error
11 | let compare = equal_5();
| ------- consider giving `compare` a type
12 | println!("eq {}", compare(6));
| ^^^^^^^^^^ cannot infer type
|
= note: type must be known at this point
See: https://doc.rust-lang.org/stable/rust-by-example/trait/impl_trait.html
Currently T simply describes a type, which in this case implements the Fn trait. In other words, T isn't a concrete type. In fact with closures, it's impossible to declare a concrete type because each closure has it's own unique type (even if two closures are exactly the same they have different types.)
To get around directly declaring the type of the closure (which is impossible) we can use the impl keyword. What the impl keyword does is convert our description of a type (trait bounds) into an invisible concrete type which fits those bounds.
So this works:
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
let compare = equal_5();
println!("eq {}", compare(6));
One thing to note is we can also do this dynamically. Using boxes and the dyn trait. So this also works, however incurs the associated costs with dynamic resolution.
fn equal_5() -> Box<dyn Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}
let compare = equal_5();
println!("eq {}", compare(6));
The compiler seems to be complaining that it's expecting a type parameter but finds a closure instead. It knows the type, and doesn't need a type parameter, but also the size of the closure object isn't fixed, so you can either use impl or a Box. The closure will also need to use move in order to move the data stored in x into the closure itself, or else it wont be accessible after equal_5() returns, and you'll get a compiler error that x doesn't live long enough.
fn equal_5() -> impl Fn(u32) -> bool {
let x:u32 = 5;
move |z| z == x
}
or
fn equal_5() -> Box<Fn(u32) -> bool> {
let x:u32 = 5;
Box::new(move |z| z == x)
}

How to do Higher Order Composition in Rust?

I have this function that works:
fn compose<A, B, C>(f: impl Fn(A) -> B, g: impl Fn(B) -> C) -> impl Fn(A) -> C {
move |x: A| g(f(x))
}
I'd like to use currying in this situation, so that I can do:
/* THIS */
compose(f)(g)(x)
/* Instead of this */
compose(f, g)(x)
Is it even reasonable to think about making a macro such that this is possible?
compose(f)(g)(h)ยทยทยท(x)
I've managed to get something that's kinda similar to what I want:
fn compose<A, B, C, F: 'static, G: 'static>(f: F) -> impl Fn(G) -> Box<dyn Fn(A) -> C>
where
F: Fn(A) -> B + Copy,
G: Fn(B) -> C + Copy,
{
move |g: G| Box::new(move |x: A| g(f(x)))
}
let inc = |x| x + 1;
let mult2 = |x| x * 2;
let inc_compose = compose(inc);
println!("{}", inc_compose(mult2)(3)); // 8
Now there's a new problem: when creating a higher-order function based on my compose function, I need to give the function a type dependent on another function:
let inc = |x: usize| x + 1;
let mult2 = |x: usize| x * 2;
let mult3 = |x: usize| x * 3;
let inc_compose = compose(inc);
println!("{}", inc_compose(mult2)(3)); // 8
println!("{}", inc_compose(mult3)(3)); // ERROR: [rustc E0308] [E] mismatched types
Is there a way to avoid this error?
None of these similar posts answer my question:
How do I emulate Lisp (apply) or (curry) in Rust?
How to implement a multiple level currying function in Rust?
How to invoke a multi-argument function without creating a closure?
The main reason is that I want currying to get the ability to do point-free programming.
In Rust, currying is hard. The strict type system, lifetimes, and nested impl traits not existing all conspire to ruin your day when you try. However, it is possible to create a macro to curry functions, and I did so for code golf at one point. The ungolfed version is here:
macro_rules! curry{
(
$f:ident
$(
($args:ident : $types:ty)
)*
) => {
$(move |$args: $types|)*
$f(
$($args),*
)
}
}
This matches on expressions of the form name(arg1, type1)(arg2, type2)...(argN, typeN) and returns a chain of move closures leading to the function call. Most of the time, however, you can just use _ for the type and let inference figure it out. Using it with compose is simple:
let inc = |x| x as u32 + 1;
let double = |x| x * 2;
let curried = curry!(compose(f: _)(g: _));
assert_eq!(curried(inc)(double)(7), 16);
The code generated by the macro, in this case, looks like this:
move |f: _| move |g: _| compose(f, g)
It simply takes the supplied name and type and pastes it into the closure heads, so you can use it to force arguments for generic functions into concrete types.
Playground

Error message with unboxed closures

This small FizzBuzz program using unboxed closures gives a rather mysterious error message.
fn fizzbuzz<F: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: F, bs: &str) {
for i in range(1i64, n+1) {
match (f(i), b(i)) {
(true, true) => println!("{:3}: {}{}", i, fs, bs),
(true, _) => println!("{:3}: {}", i, fs),
(_, true) => println!("{:3}: {}", i, bs),
_ => (),
}
}
}
fn main() {
fizzbuzz(30,
|&: i: i64| { i % 3 == 0 }, "fizz",
|&: j: i64| { j % 5 == 0 }, "buzz");
}
Error message:
<anon>:15:14: 15:40 error: mismatched types: expected `closure[<anon>:14:14: 14:40]`, found `closure[<anon>:15:14: 15:40]` (expected closure, found a different closure)
<anon>:15 |&: j: i64| { j % 5 == 0 }, "buzz");
^~~~~~~~~~~~~~~~~~~~~~~~~~
error: aborting due to previous error
Could someone describe the error please? Thanks.
This piece of code demonstrates the essence of the problem:
fn show_both<S: Show>(x: S, y: S) {
println!("{} {}", x, y);
}
You can only call it with both arguments of the same type, i.e. this is allowed:
let x: i32 = 10;
let y: i32 = 20;
show_both(x, y);
But this is not:
let x: i32 = 10;
let y: f64 = 20.0;
show_both(x, y);
This is fairly natural: you specified that both of the parameters must be of the same type, even though this type can be arbitrary as long as it implements Show.
You have essentially the same thing in your code:
fn fizzbuzz<F: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: F, bs: &str)
You declared that both f and b must have the same type. However, for each unboxed closure the compiler generates a different type - this is quite natural as well, given that different closures can capture different variables.
You need to specify different type parameters in order to be able to pass different closures:
fn fizzbuzz<F1, F2>(n: i64, f: F1, fs: &str, b: F2, bs: &str)
where F1: Fn(i64) -> bool,
F2: Fn(i64) -> bool
Each unboxed closure definition creates a completely different type. This makes each of the closures defined in main a different type. Your fizzbuz function, on the other hand, requires each of the closures passed to it to be the same type, F. If you change fizzbuzz's signature to:
fn fizzbuzz<F: Fn(i64) -> bool, G: Fn(i64) -> bool>(n: i64, f: F, fs: &str, b: G, bs: &str)
your code will typecheck.
Basically, the <F: Fn(i64) -> bool> syntax doesn't create a wildcard for types that implement the trait parameter (Fn(i64) -> bool), but declares a single type which must satisfy the trait parameter and be the same type everywhere it is used. Unboxed closure definitions must be different types both because the may wrap different environments but also because they dispatch to different functions (that is, each has a different body). As a result, fizzbuzz needs two different type parameters to accommodate the two closure types.

Resources