-
-
Notifications
You must be signed in to change notification settings - Fork 31
Implement Clone for IntoIter
#57
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
Conversation
|
Furthermore using RC doesn't seem like a real possibility here. By doing this the iterator would turn read-only and non-consuming, thus not working anymore like |
I think it's possible to use the same backing storage and clone the individual items upon iteration (a code path for that already exists). That would save the extra top-level allocation. |
|
While cloning items during iteration could technically work, I believe it would change the semantics - |
|
That argument doesn't really make sense to me. When there is no other clone of For what it's worth, the existing Lines 1139 to 1151 in 9639e9f
Of course, |
|
I believe this cannot be implemented like this. I attempted to do so, but you end up violating Rust’s move semantics: This results in two independent drops of the same elements, which is undefined behavior. The UB checker catches it as overlapping or invalid pointer operations during subsequent moves. To implement Clone soundly, the iterator would need to either:
The latter doesn't seem like a valid option because, as I stated originally, this is NOT how a Anything that allows multiple |
|
Certainly we can't do multiple However, I think cloning on yield is a perfectly fine option.
I tried to argue why I believe this is okay in my previous message, but you did not really respond to my argument except for saying that it's not how it should operate. It already happens when you do |
|
You're right that in cases where the My concern is mainly semantic: an |
|
I'm not sure what you mean with "read-only". Under well-behaved usage, I think you wouldn't be able to observe any difference between The only way to observe when something is cloned is with interior mutability or impure clone implementations. These are things that need to be very carefully mixed with any kind of reference counting (same when using Perhaps you could show a concrete code example that you think would behave differently under both options? |
|
You can't implement
These are some simple reasonings for the two implementations I can think of. If you avoid simple, dumb, eager cloning that is. No edge case needs to be presented, I don't think you can implement it like so for the every generic, "stable" use. If you see any other way to go about this let me know, I can try to implement it. But I've tried the both of these implementations already. |
|
Thanks for the detailed reply, that makes your point clearer. I think there are three relevant variants of the clone-on-yield idea to distinguish:
So (1) disqualifies because of its semantics (I think this was your main concern) and (3) disqualifies because of feasibility. For me (2), would be fine in terms of semantics. It's already how Now, the remaining question is whether (2) is feasible to implement. I believe the answer is yes, but it's possibly I'm missing something. Basically, the problematic case is when an originally unique iterator is cloned. Then, we need to make it shared, but some of the elements have already been moved out. To avoid double-dropping, we would need to have an extra field in I'm not sure whether it's worth it to implement it like this. That said, I also don't like the implementation that immediately allocates new backing storage. It's not what I would intuitively expect from |
|
Ah yes, now I see what you mean. The second idea might be possible to implement in theory, though I think it still leads to the problem I pictured on the first situation. If you have 2 Given this rationale is correct, I think we'll need to either give the dumb implementation or just discard it altogether. Let me know what you think. |
|
If we have two |
|
So in this rationale, if we have The first idea should be doable. The second one doesn't seem so. |
|
All would have let v1 = eco_vec![1,2,3];
let v2 = v1.clone();
let a = v1.into_iter();
let b = v2.into_iter();I think it should work fine, it's just the question of whether the complexity and extra field are worth it... I'm not sure. |
|
Isn't this worse though? If we have only |
|
My point is that this is already the case regardless of your PR for |
|
Indeed, all my initial implementation does anyway is act as a helper for cloning the vector. So you think it's better to just not implement |
|
I think there's still a misunderstanding. I am speaking about ecow as it is released on crates.io right now, completely unrelated to your PR. If you have an |
|
I've decided that I'd rather not support this in ecow, as the additional field and additional complexity do not feel worth it for the rather niche use case of cloning the iterator. Thank you for the discussion and the work you've put into this, still! |
Handles #52