Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upExtending deref/index with ownership transfer: DerefMove, IndexMove, IndexSet #997
Comments
This was referenced Mar 21, 2015
japaric
referenced this issue
May 19, 2015
Closed
IndexAssign: overloading the `a[b] = c` expression #1129
This comment has been minimized.
This comment has been minimized.
|
I'd like DerefMove for similar reasons that Servo wants it: servo/servo#3868 Namely, I have an type struct Foo {
handle: my_ffi_crate::foo // foo is a *mut to an uninhabited enum
}and a "borrowed" version of that called struct BFoo<'a> {
handle: my_ffi_crate::bfoo, // bfoo is the *const equivalent of my_ffi_crate::foo
_phantom: PhantomData<&'a Foo>
}
Most of the immutable "accessor" methods of |
This comment has been minimized.
This comment has been minimized.
|
A potential problem for the design of |
This comment has been minimized.
This comment has been minimized.
|
Missing from this list is also IndexGet, which is the "returns a value" version of Index. |
This comment has been minimized.
This comment has been minimized.
|
@Gankro what is the difference between your |
This comment has been minimized.
This comment has been minimized.
|
Ah I assumed IndexMove took self by-value (given the comparison to DerefMove), but if it takes &mut self, then never mind. |
This comment has been minimized.
This comment has been minimized.
flying-sheep
commented
Mar 17, 2016
|
what does the RFCs being postponed mean? will they simply be back on track as soon as someone has made up a coherent idea of how everything should play together and writes it up? |
This comment has been minimized.
This comment has been minimized.
|
@flying-sheep it means "we're not rejecting this RFC because it's bad, now is just not the right time." This happened a lot before 1.0, so we could focus on what needed to ship in 1.0. And yes, if there's a postponed RFC, someone needs to go through and evaluate if it's still valid in its current form, or update it, and re-submit it. |
This comment has been minimized.
This comment has been minimized.
flying-sheep
commented
Mar 17, 2016
|
i’m glad that things like ndarray profit from it. generally, all data structures where “slice” views can’t be rust slices. should i try to update the “remaining Index traits” RFC (#159)? if so: |
This comment has been minimized.
This comment has been minimized.
andrewcsmith
commented
Apr 1, 2016
|
I would say that Perhaps it would be possible to use type inference to decide whether to use let some_array: [i32; 4] = [1, 2, 3, 4];
let some_slice = &some_array[0..3];
let x = some_slice[2]; // x: &i32 (default behavior)
let y: i32 = some_slice[2]; // y: i32 (would use `IndexGet` to pass by valueThis would more or less follow from the current inference of I do see the potential for compiler confusion in choosing which trait to use for a given operation, but I would at least appreciate a default implementation of I would also like to mention that even though copying-when-indexing is antithetical to C/C++, it is a very common idiom when it comes to Ruby, etc. I don't think this is a weakness in Ruby, but in fact allowing the end-user to use one idiom or other other should help ease the learning curve for people coming from dynamic languages that assume copy. One of my greatest frustrations with the Ruby language is not knowing whether array indexing was happening by-value or by-reference. I think if Rust could acknowledge both of these domains, and allow programmers the explicit option of choosing one or the other, it would go a long way. Edit: thanks @comex for pointing out that I indexed a stack array rather than a slice initially |
This comment has been minimized.
This comment has been minimized.
comex
commented
Apr 2, 2016
|
@andrewcsmith ( |
This comment has been minimized.
This comment has been minimized.
VFLashM
commented
Jun 15, 2016
TheoryBoth deref and index are for types containing values of other types. They allow to conveniently access contained value. There are two cases currently supported:(1) accept ref, return ref (Deref/Index) There is one case requested for derefs:(3) consume value, return value (DerefMove?,IndexMove?) It's an open question whether or not we need Index counterpart. I personally don't think it will be very useful. There are two more index cases requested:(4) accept ref, return value (IndexGet?) They can be used for collections not actually storing value instances (e.g. bit array setting/returning bools). PracticeNow let's get to practice, and please correct me if I'm wrong about current rules. DerefCurrent deref rulesCurrent manual deref follows simple rules:
Autoderef follows the same rules, but also depends on context:
Proposed deref rulesDeref rules proposed in #178, in short, are: try to move copyables, try to ref non-copyables, otherwise use whatever possible. Proposed manual deref rules:
Proposed autoderef rules:
If rule condition is satisfied, but required trait is not available, then that's a failure and compiler should not try to apply other rules (that's the only thing different from #178) It is possible to support DerefGet/DerefSet, but, then again, it's noticeably ramps complexity and likely not very useful. IndexingCurrent indexing rulesIndexing is more or less follow deref, but is generally simpler, because there is no autoderef counterpart. Current rules for indexing:
Proposed indexing rulesThis extends both #159 and #1129, adds more details and answers some unresolved questions. Main problem is IndexGet. Option of having it adds lots of ambiguity into rules. I propose to make IndexGet and Index/IndexMut/IndexMove mutually exclusive. With mutually exclusive IndexGet and Index/IndexMut/IndexMove, indexing rules actually become pretty simple. For types implementing IndexGet:
For all other types:
Just like with derefs, if rule condition is satisfied, but required trait is not available, then that's a failure and compiler should not try to apply other rules. Note that I'm not sure if we need IndexMove (consume value, return value), but I list it here for completeness sake. Indexing examples// Bits is a tightly packed bits array, implements IndexGet/IndexSet
println!("first bit is: {}", bits[0]); // bits.index_get(0)
bits[1] = true; // bits.index_set(1, true)
bits[2] ^= true; // bits.index_set(2, (bits.index_get(2) ^ true))
let tref = &bits[3] // &bits.index_get(3), reference to temporary
// Array implements Index/IndexMut/IndexSet
println!("first element is: {}", array[0]) // *array.index(0)
let second = &array[1] // array.index(1), ref of second element
let third = &mut array[2] // array.index_mut(2), mutable ref of third element
array[3] = 2; // array.index_set(3, 2)
array[4] += 3; // (*array.index_mut(4)) += 3
// Map implements:
// Index/IndexMut for Index types where Key impl Borrow<Index>
// IndexSet/IndexMove for Index types where Key impl From<Index>
let vref = &array["key"] // array.index("key"), ref of value
let vrefmut = &mut array["key"] // array.index_mut("key"), mutable ref of value
map["new key"] = 1; // map.index_set("new key", 1), creates new entry
map["new key"] += 2 // (*map.index_mut("new key")) += 2, modifies existing entry
return map["key"]; // map.index_move("key"), consumes map
// failures:
&map["missing key"] // map.index("missing key"), fails
&mut map["missing key"] // map.index_mut("missing key"), fails
map["missing key"] += 2 // (*map.index_mut("missing key")) += 2, does not insert value, failsP.S.
|
This comment has been minimized.
This comment has been minimized.
spiveeworks
commented
Jun 8, 2017
|
In the case of indexing, what would happen to would it become obviously it would be nice if it became |
This comment has been minimized.
This comment has been minimized.
VFLashM
commented
Jun 8, 2017
|
Wow, it's been a while. You're absolutely right, that's a very important use case I missed. I guess rules have to be modified like this to make it work:
I hate to see how complex it gets, but still can't find a more usable solution. |
This comment has been minimized.
This comment has been minimized.
chpio
commented
Jun 8, 2017
•
This comment has been minimized.
This comment has been minimized.
coder543
commented
Oct 22, 2017
•
|
Given that we're in the I also don't see a clear summary of what is blocking this, in case someone wanted to hack on this, which I think means the design work was never completed? Just trying to get a feel for the situation. |
This comment has been minimized.
This comment has been minimized.
burdges
commented
Oct 22, 2017
•
|
IndexGet plus IndexSet should not be invoked together, say by A priori, I'd think indexing into collection types should return |
This comment has been minimized.
This comment has been minimized.
vorner
commented
Jan 17, 2018
|
Hello. I'd like this to move forward (especially because of |
sfackler
referenced this issue
Feb 13, 2018
Open
Support returning elements from an array by-value #48174
Centril
added
T-lang
T-libs
labels
Feb 23, 2018
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 1, 2018
|
Anything happened with this lately? |
This comment has been minimized.
This comment has been minimized.
|
Random thought while getting myself up to speed---
and getting confused that the latter fails if the result type isn't copyable. This can't be caught at compile-time, since we don't actually move out of |
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
|
Err, right. I forget that case is useful. In that case, I meant |
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 1, 2018
|
@alercah Moving out is consuming it, as far as I can tell. Unless you mean something different by "consuming it"... |
This comment has been minimized.
This comment has been minimized.
|
Ah, |
This comment has been minimized.
This comment has been minimized.
|
Ahhh, right, ok! That makes sense, then. :) What's the use case of |
This comment has been minimized.
This comment has been minimized.
|
I think IndexMove is more of an intellectual curiosity than a thing we have
a concrete usecase for.
…On Tue, May 1, 2018 at 9:12 PM, Alexis Hunt ***@***.***> wrote:
Ahhh, right, ok! That makes sense, then. :)
What's the use case of IndexMove, then?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#997 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABFY4LLu26WeXqHBvZ9Qzqm68KqYycWEks5tuQf1gaJpZM4Dybu7>
.
|
This comment has been minimized.
This comment has been minimized.
alecmocatta
commented
May 2, 2018
|
I was under the impression that IndexMove was consuming the container:
rather than the current nicest way (as far as I'm aware?)
|
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 2, 2018
|
Wouldn’t it do the equivalent of |
This comment has been minimized.
This comment has been minimized.
alecmocatta
commented
May 2, 2018
•
|
@alexreg It is equivalent to the extent that it returns a The IndexMut I described consumes the collection, but need not perform the potentially expensive shifting. As it's been consumed, one can no longer use it nor the other elements it might have contained. |
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 2, 2018
|
@alecmotta Right. But with |
This comment has been minimized.
This comment has been minimized.
coder543
commented
May 2, 2018
|
After a single IndexMove, the entire array is moved, so you can’t access any elements at all. IndexMove consumes the container. Honestly, I’m not sure what that’s useful for, but it isn’t doing anything complicated like you’re describing. |
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 2, 2018
|
Oh, I see. Well it could be useful if e.g. you need to sort a |
This comment has been minimized.
This comment has been minimized.
vorner
commented
May 3, 2018
|
I understand the biggest motivation is |
This comment has been minimized.
This comment has been minimized.
alexreg
commented
May 3, 2018
•
|
@vorner Right. |
This comment has been minimized.
This comment has been minimized.
|
I wonder about doing something like this: #[lang = "deref_move"]
trait DerefMove {
type Target;
fn deref_move(self) -> Self::Target;
}
impl<'a, T> DerefMove for &'a T
where
T: ?Sized + std::ops::Deref,
{
type Target = &'a T::Target;
fn deref_move(self) -> Self::Target {
self
}
}
impl<'a, T> DerefMove for &'a mut T
where
T: ?Sized + std::ops::DerefMut,
{
type Target = &'a mut T::Target;
fn deref_move(self) -> Self::Target {
self
}
}
impl<T> DerefMove for Box<T> {
type Target = T;
fn deref_move(self) -> T {
*self
}
}Remove |
nikomatsakis commentedMar 21, 2015
It is clear that there is a need for the ability to move out of smart pointers and indexable things (
DerefMove,IndexMove). The other frequently desired option is toIndexSet, which would be a special-cased version for indexing in this situation:currently, this is handled via
IndexMut, but that is sub-optimal, because if thekeyis not already part of themap, the result is a panic.Basic plan
DerefMove/IndexMove/IndexSet should layer on top of the traits we have now. One needs to be careful here because of subtle interactions with autoref and so forth.
Postponed RFCs
map[key] = value)