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

ArrayView should be covariant over lifetime #1332

Open
patengel opened this issue Oct 5, 2023 · 4 comments
Open

ArrayView should be covariant over lifetime #1332

patengel opened this issue Oct 5, 2023 · 4 comments

Comments

@patengel
Copy link

patengel commented Oct 5, 2023

Take a look at the following example:

fn reference_covariant<'a>(x: &'static f64) -> &'a f64 {
    x
}

fn arrayview_covariant<'a>(x: ArrayView1<'static, f64>) -> ArrayView1<'a, f64> {
    x
}

The first compiles fine, the second one does not compile and give the following error message:

fn arrayview_covariant<'a>(x: ArrayView1<'static, f64>) -> ArrayView1<'a, f64> {
                       -- lifetime `'a` defined here
   x
   ^ returning this value requires that `'a` must outlive `'static`

note: requirement occurs because of the type `ArrayBase<ViewRepr<&f64>, Dim<[usize; 1]>>`, which makes the generic argument `ViewRepr<&f64>` invariant
note: the struct `ArrayBase<S, D>` is invariant over the parameter `S`

The problem is caused by the usage of S::Elem inside the definition of ArrayBase.

I stumbled across this problem, since I used ArrayView deep inside a data structure which should be covariant.
As a user of ndarray I would assume that ArrayViews behave the same as Rust references, but I see fixing this bug is hard without interface changes.
Is there an easy work-around for such problems? I currently do not know of any...

@bluss
Copy link
Member

bluss commented Oct 6, 2023

Does the method reborrow help in your case? https://docs.rs/ndarray/latest/ndarray/type.ArrayView.html#method.reborrow

@patengel
Copy link
Author

patengel commented Oct 9, 2023

No sadly it does not. The functions in the code work on references to the complete data structure, and therefore using reborrow would require to duplicate the complete data structure.

@0xbe7a
Copy link

0xbe7a commented Jan 17, 2024

Edit: After looking at it, this is probably related to #1341

I have minimized it to this snippet: If either the Drop implementation is removed or ArrayBase does not have <S as MyTrait>::Elem and S as elements at the same time, the covariance works. Looks to me like a limitation of the Rust compiler

fn x<'s>(x: &'s ArrayBase<OwnedRepr<&'s str>>) {
    ()
}

pub struct ArrayBase<S>
where
    S: MyTrait, {
    pub data: S,
    pub ptr: <S as MyTrait>::Elem,
}

trait MyTrait {
    type Elem;
}

pub struct OwnedRepr<A>(A);

impl<A> Drop for OwnedRepr<A> {
    fn drop(&mut self) {
        todo!()
    }
}

impl<T> MyTrait for OwnedRepr<T> {
    type Elem = T;
}

fn main() {
    let elem = "abc";

    let data = OwnedRepr(elem);

    let input = ArrayBase {
        data,
        ptr: elem
    };

    x(&input);
}

@bluss bluss added help wanted and removed question labels Mar 9, 2024
@bluss
Copy link
Member

bluss commented Mar 9, 2024

put this in order after implementing ArrayRef #879, probably not going to be possible though (?) without new Rust features.

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

No branches or pull requests

4 participants