How to get many references to one object, using SlotMap? - rust

enum List<'a> {
Cons(isize, &'a List<'a>),
Nil,
}
fn main() {
use List::*;
use slotmap::SlotMap;
let mut table = SlotMap::new();
let nil = table.insert(Nil);
table.insert(Cons(1, table[nil]));
}
SlotMap<K: Key, V>'s insert is
pub fn insert(&mut self, value: V) -> K
and its impl<K: Key, V> Index<K> is
fn index(&self, key: K) -> &V
So surely since I insert List into table, table[key] should return &List right?
Why am I getting this error:
error[E0308]: mismatched types
--> src/main.rs:11:26
|
11 | table.insert(Cons(1, table[nil]));
| ---- ^^^^^^^^^^
| | |
| | expected `&List<'_>`, found enum `List`
| | help: consider borrowing here: `&table[nil]`
| arguments to this enum variant are incorrect
|
How should I actually be using SlotMap to get many (immutable) references to SlotMap-owned objects?

Yes, index() returns a &V, but the operator [] works such that a[b] is equivalent to *a.index(b).
Which is handy, because when you write for example an array:
let mut a = [1,2,3];
a[0] = 0;
you don't want to write *a[0] = 0;! And consider arrays of arrays... *(*m[0])[1] = 0;, that wouldn't be pretty.
So if you want the reference to the value just reborrow (that is what the compiler suggests):
table.insert(Cons(1, &table[nil]));
Or alternatively call index manually:
table.insert(Cons(1, table.index(nil)));
But that begs the question, if you are adding all your lists and partial lists to the slotmap, why not:
enum List {
Cons(isize, Key),
Nil,
}
And get rid of lifetime issues forever?

Related

Cannot understand where a reference to a local value is being returned in Rust

I'm struggling to understand where I'm returning a reference to a local value in this function (full code: https://gist.github.com/9f88f9ded8f2f6a1f3b839422a521073):
fn encode_initial_configs<'a, TSym, NTSym>(
alpha: impl IntoIterator<Item = TSym> + 'a,
grammar: &'a OPGrammar<TSym, NTSym>,
chunk_size: usize,
) -> impl Iterator<Item = GPUParseConfig> + 'a
where
TSym: Eq + std::hash::Hash + Clone,
NTSym: Eq + Clone,
{
assert_ne!(chunk_size, 0, "`chunk_size` must be non-zero.");
let mut alpha_chunks = grammar
.encode_iterator(alpha)
.chunks(chunk_size)
.into_iter()
.map(|chunk| chunk.collect_vec())
.fuse();
let curr_chunk = alpha_chunks.next();
InitialConfigs {
alpha_chunks,
last_sym: 0,
curr_chunk,
}
}
The compiler complains about the value returned in the bottom:
error[E0515]: cannot return value referencing temporary value
--> src/par_parse.rs:77:5
|
70 | let mut alpha_chunks = grammar
| ____________________________-
71 | | .encode_iterator(alpha)
72 | | .chunks(chunk_size)
| |___________________________- temporary value created here
...
77 | / InitialConfigs {
78 | | alpha_chunks,
79 | | last_sym: 0,
80 | | curr_chunk,
81 | | }
| |_____^ returns a value referencing data owned by the current function
|
= help: use `.collect()` to allocate the iterator
For more information about this error, try `rustc --explain E0515`.
But the alpha_chunks iterator returned as part of the InitialConfigs instance is obtained by moving every intermediate iterator into the next one. Where is this reference?
EDIT: encode_iterator might be relevant:
pub fn encode_iterator<'a>(
&'a self,
s: impl IntoIterator<Item = TSym> + 'a,
) -> impl Iterator<Item = u32> + 'a {
s.into_iter().map(|sym| self.encode_term(sym))
}
The culprit seems to be .into_iter(), which instead of consuming the result of .chunks(chunk_size), borrows it. In fact, reading the itertools code, IntoIterator is impl'd for &'a IntoChunks<I>, which is the type of the result of chunks. Furthermore, the borrowed reference to IntoChunks is stored in the returned Chunks struct, which is then stored into the iterator returned by map, and so on. A possible solution could be finding or implementing a chunk iterator that can be moved directly into map and does not hold references to local values.
Short answer: You are returning reference to alpha chunk
What's happening?
Let's look at this statement:
let mut alpha_chunks = grammar
.encode_iterator(alpha)
.chunks(chunk_size)
.into_iter()
.map(|chunk| chunk.collect_vec())
.fuse();
Here are the diffusion of statement:
grammer refer to the variable passed into the function itself
endoe_iterator() returns an iterator which which yields the item that is passed as argument. But note that iterator is local in itself, it just yields value that is not local
chunks(), into_iterator(), map(), fuse() all this just manipulate the iterator and keep re-making new iterators type
final iterator of above statement will be stored in alpha_chunks variable which is also local
So you realize that iterators are lazy i.e they don't compute anything unless called with come methods that actually make them to like collect() method. But in you case you never "collected" anything from iterator and the function just return the iterator itself which is local

Chain iterators to references of different lifetimies

I want to build a recursive function for traversing a tree in Rust. The function should always get the next element and an iterator over references to the ancestor elements.
For the iterator over ancestor elements, one could in principle use the chain and once methods. Consider the following simple example, where the tree is jsut a Vec (for the purpose of this demonstration):
fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
where
I: Iterator<Item = &'a String> + Clone,
{
if let Some(next) = remaining.pop() {
let next_ancestors = ancestors.chain(std::iter::once(&next));
proceed(remaining, next_ancestors);
}
}
Playground
This fails to compile because &next has a shorter lifetime than 'a:
error[E0597]: `next` does not live long enough
--> src/lib.rs:6:62
|
1 | fn proceed<'a, I>(mut remaining: Vec<String>, ancestors: I)
| -- lifetime `'a` defined here
...
6 | let next_ancestors = ancestors.chain(std::iter::once(&next));
| --------------------------------^^^^^--
| | |
| | borrowed value does not live long enough
| argument requires that `next` is borrowed for `'a`
7 | proceed(remaining, next_ancestors);
8 | }
| - `next` dropped here while still borrowed
I tried to overcome this by adding an explicit second lifetime 'b: 'a and forcing an explicit reference by something like let next_ref: &'b String = &next, but that yields a (different) error message as well.
One solution I came up with was to call map as follows:
let next_ancestors = ancestors.map(|r| r).chain(std::iter::once(&next));
As pointed out by #trentcl, this doesn't actually solve the problem, as the compiler then gets stuck in an infinite loop when compiling proceed for all the nested Chains when one actually tries to call the function.
The pieces of solution are already around, just to summarize:
As you already know, using map(|r| r) "decouples" the lifetime requirement of ancestors
from the lifetime of &next.
As already stated in the comments, fixing
the infinite recursion is a matter to change ancestors into a trait object.
fn proceed<'a>(mut remaining: Vec<String>, ancestors: &mut dyn Iterator<Item = &'a String>) {
if let Some(next) = remaining.pop() {
let mut next_ancestors = ancestors.map(|r| r).chain(std::iter::once(&next));
proceed(remaining, &mut next_ancestors);
}
}
fn main() {
let v = vec!["a".to_string(), "b".to_string()];
proceed(v, &mut std::iter::empty());
}

Cannot use the entry API to mutate a HashMap using a reference as the key inside of a function

I'm trying to get a handle to an element in a mutable HashMap reference where the keys are &str.
In the example below, I'm trying to get value dict[key] so I can mutate it. How do I do this?
I've tried:
dict.entry(key): lifetime mismatch
dict.entry(&String::from(key)): borrowed value does not live long enough
e.g. this:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
let num = dict.entry(&String::from(key)).or_insert(0);
*num += 1;
return 42;
}
Errors out with:
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:4:27
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| - let's call the lifetime of this reference `'1`
4 | let num = dict.entry(&String::from(key)).or_insert(0);
| ------------^^^^^^^^^^^^^^^^^- - temporary value is freed at the end of this statement
| | |
| | creates a temporary which is freed while still in use
| argument requires that borrow lasts for `'1`
Link the lifetime of the key argument to the lifetime of the keys in the HashMap:
use std::collections::HashMap;
fn do_thing<'a>(key: &'a str, dict: &mut HashMap<&'a str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
dict.entry(key)
The error message for this version helps understand the problem:
use std::collections::HashMap;
fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
*dict.entry(key).or_insert(0) += 1;
42
}
error[E0623]: lifetime mismatch
--> src/lib.rs:4:17
|
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
| ---- ----
| |
| these two types are declared with different lifetimes...
4 | *dict.entry(key).or_insert(0) += 1;
| ^^^ ...but data from `key` flows into `dict` here
Specifically, entry will store key in the HashMap, but the value referenced by key might become invalid before the HashMap does. If that happened, the HashMap would contain a dangling reference, pointing to invalid memory. That's exactly what Rust's borrow checker prevents.
See also:
When is it required to use lifetimes?
Why are explicit lifetimes needed in Rust?
dict.entry(&String::from(key))
This can never work here, for much the same reason.
See also:
Return local String as a slice (&str)

How to create a function that creates a Cartesian product Iterator from an Iterator of Iterators?

If I want to create a Cartesian product of a list of lists in Haskell, I can do this:
product [] = [[]]
product (xs:xss) = concatMap (\k -> map (k:) (product1 xss)) xs
or even this:
sequence xss
I'm trying to implement an efficient iterator that would do the same in Rust, but I'm not sure what is wrong with my attempt:
use std::iter::{empty, once};
fn product<T, I, V>(xss: I) -> Box<Iterator<Item = Iterator<Item = T>>>
where
T: Clone,
V: IntoIterator<Item = T>,
I: IntoIterator<Item = V>,
{
Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
}))
}
fn main() {
let data = vec![[1, 2, 3], [10, 20, 30], [100, 200, 300]];
let it: Vec<Vec<u32>> = product(data).collect();
println!("{:?}", it);
}
(playground)
Produces these errors:
error[E0308]: mismatched types
--> src/main.rs:10:9
|
10 | xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::iter::Once`, found struct `std::iter::FlatMap`
|
= note: expected type `std::iter::Once<std::iter::Empty<T>>`
found type `std::iter::FlatMap<<V as std::iter::IntoIterator>::IntoIter, std::iter::Map<std::iter::Once<std::iter::Empty<T>>, [closure#src/main.rs:10:45: 10:67 x:_]>, [closure#src/main.rs:10:33: 10:68 acc:_]>`
error[E0271]: type mismatch resolving `<std::iter::Once<std::iter::Empty<T>> as std::iter::Iterator>::Item == std::iter::Iterator<Item=T>`
--> src/main.rs:9:5
|
9 | / Box::new(xss.into_iter().fold(once(empty()), |acc, xs| {
10 | | xs.into_iter().flat_map(|x| acc.map(|ys| ys.chain(once(x))))
11 | | }))
| |_______^ expected struct `std::iter::Empty`, found trait std::iter::Iterator
|
= note: expected type `std::iter::Empty<T>`
found type `std::iter::Iterator<Item=T>`
= note: required for the cast to the object type `std::iter::Iterator<Item=std::iter::Iterator<Item=T>>`
error[E0277]: the trait bound `[{integer}; 3]: std::iter::Iterator` is not satisfied
--> src/main.rs:16:29
|
16 | let it: Vec<Vec<u32>> = product(data).collect();
| ^^^^^^^ `[{integer}; 3]` is not an iterator; maybe try calling `.iter()` or a similar method
|
= help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 3]`
= note: required because of the requirements on the impl of `std::iter::IntoIterator` for `[{integer}; 3]`
= note: required by `product`
error: the `collect` method cannot be invoked on a trait object
--> src/main.rs:16:43
|
16 | let it: Vec<Vec<u32>> = product(data).collect();
| ^^^^^^^
The first error is giving me the feeling that Rust cannot even create a lazily consumed iterator with fold because Empty<T> is an Iterator<Item = T> (at least conceptually), but I hope I'm wrong.
For what its worth, the Itertools crate implements a workable cartesian product function:
use itertools::Itertools;
let it = (0..2).cartesian_product("αβ".chars());
itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]);
The first reason your approach is bound to fail is because you're trying to transpose an algorithm designed to work on lists into an algorithm working on iterators. Lists are suitable for a functional approach, iterators aren't, because they have a state. The next(&mut self) function won't return the same value each time it's called with the same argument, whereas a next(x:xs) function will. This is the reason why the implementation found in itertools clones iterators: to save their initial state and recover it for the next iteration over the set.
The second reason, the one behind the error messages, is that you're fighting against Rust's type system. The result values of all your calls to iterator functions (fold, flat_map, etc.) aren't trait objects but 'concrete types'. For instance iterator.fold(init, fn)'s result type is init's type. That's why the compiler complains when you pass fold a lambda that doesn't return a std::iter::Empty<T>.
But it gets worse. You could imagine to coerce or cast that std::iter::Empty<T> into a trait object. Alas, object safety is required. To put it in a nutshell, "A good intuition is “except in special circumstances, if your trait’s method uses Self, it is not object-safe.". But iterators' main method is next(&mut self).

How can I implement a trait using existing function implementations? [duplicate]

This program dies because of infinite recursion:
use std::any::Any;
trait Foo {
fn get(&self, index: usize) -> Option<&Any>;
}
impl Foo for Vec<i32> {
fn get(&self, index: usize) -> Option<&Any> {
Vec::get(self, index).map(|v| v as &Any)
}
}
fn main() {
let v: Vec<i32> = vec![1, 2, 4];
println!("Results: {:?}", v.get(0))
}
The compiler itself warns about this:
warning: function cannot return without recurring
--> src/main.rs:8:5
|
8 | fn get(&self, index: usize) -> Option<&Any> {
| _____^ starting here...
9 | | Vec::get(self, index).map(|v| v as &Any)
10 | | }
| |_____^ ...ending here
|
= note: #[warn(unconditional_recursion)] on by default
note: recursive call site
--> src/main.rs:9:9
|
9 | Vec::get(self, index).map(|v| v as &Any)
| ^^^^^^^^^^^^^^^^^^^^^
= help: a `loop` may express intention better if this is on purpose
Why does universal call syntax not work in this case? The compiler does not understand that I want to call Vec::get not Foo::get.
How can I fix this, if I do not want to change function names?
To specify which method to call, whether inherent or provided from a trait, you want to use the fully qualified syntax:
Type::function(maybe_self, needed_arguments, more_arguments)
Trait::function(maybe_self, needed_arguments, more_arguments)
Your case doesn't work because Vec doesn't have a method called get! get is provided from the Deref implementation to [T].
The easiest fix is to call as_slice directly:
self.as_slice().get(index).map(|v| v as &Any)
You could also use the fully qualified syntax which requires the angle brackets in this case (<...>) to avoid ambiguity with declaring an array literal:
<[i32]>::get(self, index).map(|v| v as &Any)
universal call syntax
Note that while Rust originally used the term universal function call syntax (UFCS), the usage of this term conflicted with the existing understood programming term, so the use of it is not suggested. The replacement term is fully qualified syntax.

Resources