-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
'Contains' method for ranges #1434
Conversation
|
||
This trait provides the method `.contains()` and implements it for all the Range types. | ||
|
||
## Add a `.contains(item: Self::Item)` iterator method |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.contains<I: PartialEq<Self::Item>>(i: I)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes.
Well, I’m not sure this is very necessary. What are usecases for this method? Would it be used oftenly (I didn’t find myself needing that, ever)? Since the start and end bounds are public fields, I guess this could be prototyped out-of-std. |
Ideally, the answer to that question is the "Motivation" section of the RFC. Some examples of desired use should be there as well. |
Will extend the motivation section. |
Should this apply to |
I don't really see why that's useful, but it makes sense for the sake of consistency. |
I was still waiting for specialization to hit but I wanted to propose this as well as part of a greater proposal to get I understand there's a certain apprehension around simple syntax changes like this that don't solve major problems. It's good to be careful. However, in this case, I think the risks and costs are very low as we don't need to add any keywords and the concept that The advantage for adding this method (with or without the added syntax) on ranges is basically not having to repeat yourself what variable should be within the boundaries given by the range as opposed to two separate checks. It's also not very useful on ranges other than |
The Where would |
@ehiggs Ever since collections reform, there's been a sort-of moratorium on traits for collections. The primary reasoning, if I remember correctly, was to hold off until HKT. If this RFC were to move forward, I would expect |
I don't really think a I am, personally, in favor of a method for the Iterator trait, since this pattern is common when dealing with iterators, and using |
I tend to like remaining conservative on adding new methods just because they "make sense" without a clear pressing desire to actually use them. In this case, the lack of a With that said, a The |
That makes sense (couldn't resist). Sorry if my wording wasn't clear: The reason why I think these methods should be added is that they're very common, and they look much better than just plain "compare and check" way. Let me give an example: fn is_teenager(age: u32) -> bool {
(13..20).contains(age)
} instead of fn is_teenager(age: u32) -> bool {
age >= 13 && age < 20
} I think we can agree that the first is more readable and less verbose than the second. It's (in my experience) also less prone to off-by-one bugs (because you don't forget the
In many cases, it can be specialised. A small list of iteratables that can have this specialized for better performance: Aside from the trivial onces (Range, RangeTo, RangeFrom, RangeFull, Repeat, Once) there are:
I'm sure there are more (these just came to my mind).
When you want to know if your iterator contains some value without searching naiively through the whole iterator. The main advantage of such a method is not ergonomics, but performance. |
Somewhat agree.
I understand that. But under what circumstances do you have an iterator to a container and need to check that for membership as opposed to the original container? This is what I mean by use cases. Can you point out real code that would benefit from this? More importantly, I'm not actually convinced that performance can be reliably achieved. For example, if you have an iterator over the keys of a |
One word: Generics. Whenever you write a function or a trait that takes an iterable, you cannot rely on the underlying collection.
HashSet's iterable will just iterate over the elements in the buckets. Thus you know, at any point, what bound your contained item should satisfy. This gives O(1) performance. |
I'm not personally a fan of hand-waving "generics" as a compelling use case on its own, but I understand what you mean. Without something concrete in front of me, it's hard for me to see whether
I think I buy it. |
A quick grep from crates I've cloned on my computer a little over 4% of all iterator methods called are of the form, An example is if I want my function to take a list, in which case I let my function take
That's true. A problem which itertools, for example, has is the lack of specialisation, hence worse performance. |
One more vote for this proposal. Here is why: let number = some_computation();
number >= low && number < high
// vs
(low..high).contains(some_computation()) Actually I was surprised by the lack of |
I like this idea a lot. I use |
🔔 This RFC is now entering its week-long final comment period 🔔 |
@alexcrichton The final comment period is over? Is a decision made? |
Unfortunately the libs team didn't get a chance to discuss this last week, but we should get around to it this coming week! |
Sure! |
+1 for the Quick and dirty search for possible use cases in the rustc code:
|
The libs team discussed this RFC during triage yesterday and the decision was to merge. It sounded like there's some interesting possibilities with iterators here as well, but we concluded that in any case we'd like to have these methods regardless. Thanks again for the RFC @ticki! |
Tracking issue: rust-lang/rust#32311 |
Rendered.