Skip to content

Get a correct reference to an element from ArrayView #372

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

Merged
merged 2 commits into from
Oct 31, 2017

Conversation

termoshtt
Copy link
Member

Revival of #371
Since Index trait does not allow us to change the lifetime, I implement it as an associated function ArrayView::elem_ref and ArrayViewMut::elem_ref_mut

@bluss
Copy link
Member

bluss commented Oct 20, 2017

Good idea, will look closer at it soon

@bluss
Copy link
Member

bluss commented Oct 20, 2017

elem_ref_mut is not sound with Rust borrowing rules. This is a tricky case, where the shared and mutable reference rules don't really correspond to another.

The summary is:

  • from &'a &'b T we can get a &'b T even if 'b is a greater scope than 'a
  • from &'a mut &'b mut T we cannot get a &'b mut T because we can only get the shorter of 'a and 'b.

Instead of trying to convince anyone of that rule, here is a program that shows that elem_ref_mut allows producing two simultaneous and equal mut references:

Code link

When I run it, it has this output:

$ cargo test --test aliasing_mut -- --nocapture
running 1 test
In two references with reference 0x7f9fd79fe5cc and 0x7f9fd79fe5cc
test test ... ok

But, since this is undefined behaviour, this output is not required to be there, it could change with compiler optimizations and compiler version.

///
/// This is a replacement of `Index::index` since it forces us a wrong lifetime
/// https://github.com/bluss/rust-ndarray/issues/371
pub fn elem_ref<I: NdIndex<D>>(&self, index: I) -> &'a A {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is a good idea. We should make something that closely aligns with the design of the methods for element access that we have, I'm thinking of the Index trait and of the methods .get() and .uget().

I'd like to find a good name for this -- something that's similar to get or index. Also, we probably want an unchecked version of this method too (like uget).

///
/// This is a replacement of `IndexMut::index_mut` since it forces us a wrong lifetime
/// https://github.com/bluss/rust-ndarray/issues/371
pub fn elem_ref_mut<I: NdIndex<D>>(&mut self, index: I) -> &'a mut A {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the comment in the PR thread first. We'll have to be creative here, I don't know what we can do that is also correct with Rust's borrow checker rules.

(As a digression, it's a shame we have this problem! Slices are special in Rust, they are built in dynamically sized types. We'd like to have a custom version of that instead of what we have with the ArrayView and ArrayViewMut. We wouldn't have this problem.)

@termoshtt
Copy link
Member Author

elem_ref_mut is not sound with Rust borrowing rules.

Yes, and thanks for your careful check. This is an invalid pointer dereferencing.

I cannot find a way to keep this interface, and my answer for this problem is to consume ArrayVeiwMut like ArrayViewMut::into_slice done:

pub fn elem_ref_mut<I: NdIndex<D>>(self, index: I) -> &'a mut A { ... }

Then the two mutable reference cannot exist. (Note: We should rename this into_*.)

I'd like to find a good name for this -- something that's similar to get or index.

Do you find any name? My current candidate is elem and into_elem.

@termoshtt
Copy link
Member Author

I change the interface of &mut to use move. I also renamed into elem, uelem, into_elem, and into_elem_unchecked

/// Get a reference of a element through the view.
///
/// This is a replacement of `Index::index` since it forces us a wrong lifetime
/// https://github.com/bluss/rust-ndarray/issues/371
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can edit this doc myself. We're going to use a matter-of-fact approach, but still be positive. This is a version of index that gives out references of a longer lifetime. 😄

@bluss
Copy link
Member

bluss commented Oct 31, 2017

Thanks. If you don't mind, I'll merge this in and brood over the name myself. It's easier to get a feel for it when editing.

@bluss bluss merged commit 4b75206 into rust-ndarray:master Oct 31, 2017
///
/// This is a replacement of `Index::index` since it forces us a wrong lifetime
/// https://github.com/bluss/rust-ndarray/issues/371
pub fn uelem<I: NdIndex<D>>(&self, index: I) -> &'a A {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method must be unsafe. Sorry, I should not have merged without this fixed. I'll fix it now, though.

@termoshtt
Copy link
Member Author

Thanks for your revise and merging! and sorry for my later reply...

@termoshtt termoshtt deleted the elem_ref branch November 2, 2017 06:13
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

Successfully merging this pull request may close these issues.

2 participants