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

Lifetime troubles #1341

Closed
ViktorWb opened this issue Dec 12, 2023 · 3 comments
Closed

Lifetime troubles #1341

ViktorWb opened this issue Dec 12, 2023 · 3 comments

Comments

@ViktorWb
Copy link

ViktorWb commented Dec 12, 2023

Hi! I've been stuck on an issue for a while and can't figure out what's causing it. Not sure if there's an issue in ndarray, Rust or if I'm just missing something.

Playground

I'm trying to create a struct containing a list of arrays, where the array elements are string slices:

struct ListOfArrays<'a, D: ndarray::Dimension> {
    data: &'a [ndarray::Array<&'a str, D>],
}

fn does_not_work() {
    let arrays = [ndarray::array![""]];
    let list = ListOfArrays { data: &arrays };
}
// Error: `arrays` does not live long enough
// borrowed value does not live long enough. 
// `arrays` dropped here while still borrowed

Thing is, this same thing is totally doable with other Rust structs, for example if we replace ndarray with Vec:

struct ListOfArraysVec<'a> {
    data: &'a [Vec<&'a str>],
}

fn works() {
    let arrays = [vec![""]];
    let list = ListOfArrays { data: &arrays };
}
// Compiles!

I don't understand why this happens with ndarray, and I haven't been successful in recreating the issue with any struct other than ndarray, so that is why I'm posting here. Any guidance would be much appreciated!

@cavenditti-quaternion
Copy link

Hi, a colleague of mine wanted to understand why this happens (we're still learning Rust) so I gave a look.

I belive the problem arises from the drop() of the OwnedRepr of the BaseArray that's called automatically at the end of the scope (see here in data_repr.rs), but I might be misguided here.

Note that this happens also without the list, i.e.:

struct OneArray<'a, D: ndarray::Dimension> {
    data: &'a ndarray::Array<&'a str, D>,
}

fn does_not_work() {
    let onearray = ndarray::array![""];
    let list = OneArray { data: &onearray };
}

So far I didn't manage to find a way to specify lifetimes to make the code compile, other than making the string's lifetime static.

I hope someone else with more knowledge of ndarray's internals (and Rust) can provide a detailed explanation of what's going on 😅

@adamreichold
Copy link
Collaborator

I suspect the problem is forcing the lifetime of the array reference and that of the string references to be the same, i.e. I think

struct OneArray<'a, 'b, D: ndarray::Dimension> {
    data: &'a ndarray::Array<&'b str, D>,
}

fn does_work() {
    let onearray = ndarray::array![""];
    let list = OneArray { data: &onearray };
}

should work.

(I think that the difference between using ndarray::Array and Vec comes to the standard library having access to additional unstable language features to tell the compiler that while that Drop impl is running, it is fine with the string references dangling because it will not inspect them during drop, c.f. https://doc.rust-lang.org/nomicon/dropck.html, rust-lang/rust#34761 and https://doc.rust-lang.org/stable/src/alloc/vec/mod.rs.html#395. But note that this is a somewhat advanced topic if you are just starting with Rust.)

@ViktorWb
Copy link
Author

Thank you, those link were very helpful. Maybe this can be fixed one day when (and if) those features are stabilized, but for now, I'll probably go for two lifetimes.

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

No branches or pull requests

3 participants