Skip to content

Commit

Permalink
core: add #[must_use] attributes to iterator adaptor structs.
Browse files Browse the repository at this point in the history
It can be a little unintuitive that something like `v.iter().map(|x|
println!("{}", x));` does nothing: the majority of the iterator adaptors
are lazy and do not execute anything until something calls `next`, e.g.
a `for` loop, `collect`, `fold`, etc.

The majority of such errors can be seen by someone writing something
like the above, i.e. just calling an iterator adaptor and doing nothing
with it (and doing this is certainly useless), so we can co-opt the
`must_use` lint, using the message functionality to give a hint to the
reason why.

Fixes #14666.
  • Loading branch information
huonw committed Jul 9, 2014
1 parent b9e35a1 commit 27d18fb
Showing 1 changed file with 18 additions and 1 deletion.
19 changes: 18 additions & 1 deletion src/libcore/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,7 @@ impl<A, B, T: ExactSize<A>, U: ExactSize<B>> ExactSize<(A, B)> for Zip<T, U> {}

/// An double-ended iterator with the direction inverted
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Rev<T> {
iter: T
}
Expand Down Expand Up @@ -778,6 +779,7 @@ impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterato
}

/// A mutable reference to an iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct ByRef<'a, T> {
iter: &'a mut T
}
Expand Down Expand Up @@ -1038,6 +1040,7 @@ impl<A, T: Clone + Iterator<A>> CloneableIterator for T {

/// An iterator that repeats endlessly
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Cycle<T> {
orig: T,
iter: T,
Expand Down Expand Up @@ -1089,6 +1092,7 @@ impl<A, T: Clone + RandomAccessIterator<A>> RandomAccessIterator<A> for Cycle<T>

/// An iterator which strings two iterators together
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Chain<T, U> {
a: T,
b: U,
Expand Down Expand Up @@ -1158,6 +1162,7 @@ for Chain<T, U> {

/// An iterator which iterates two other iterators simultaneously
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Zip<T, U> {
a: T,
b: U
Expand Down Expand Up @@ -1236,6 +1241,7 @@ RandomAccessIterator<(A, B)> for Zip<T, U> {
}

/// An iterator which maps the values of `iter` with `f`
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Map<'a, A, B, T> {
iter: T,
f: |A|: 'a -> B
Expand Down Expand Up @@ -1286,6 +1292,7 @@ impl<'a, A, B, T: RandomAccessIterator<A>> RandomAccessIterator<B> for Map<'a, A
}

/// An iterator which filters the elements of `iter` with `predicate`
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Filter<'a, A, T> {
iter: T,
predicate: |&A|: 'a -> bool
Expand Down Expand Up @@ -1330,6 +1337,7 @@ impl<'a, A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Filter<'a, A,
}

/// An iterator which uses `f` to both filter and map elements from `iter`
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FilterMap<'a, A, B, T> {
iter: T,
f: |A|: 'a -> Option<B>
Expand Down Expand Up @@ -1374,6 +1382,7 @@ for FilterMap<'a, A, B, T> {

/// An iterator which yields the current count and the element during iteration
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Enumerate<T> {
iter: T,
count: uint
Expand Down Expand Up @@ -1428,6 +1437,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<(uint, A)> for Enumerat
}

/// An iterator with a `peek()` that returns an optional reference to the next element.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Peekable<A, T> {
iter: T,
peeked: Option<A>,
Expand Down Expand Up @@ -1478,6 +1488,7 @@ impl<'a, A, T: Iterator<A>> Peekable<A, T> {
}

/// An iterator which rejects elements while `predicate` is true
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct SkipWhile<'a, A, T> {
iter: T,
flag: bool,
Expand Down Expand Up @@ -1516,6 +1527,7 @@ impl<'a, A, T: Iterator<A>> Iterator<A> for SkipWhile<'a, A, T> {
}

/// An iterator which only accepts elements while `predicate` is true
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct TakeWhile<'a, A, T> {
iter: T,
flag: bool,
Expand Down Expand Up @@ -1551,6 +1563,7 @@ impl<'a, A, T: Iterator<A>> Iterator<A> for TakeWhile<'a, A, T> {

/// An iterator which skips over `n` elements of `iter`.
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Skip<T> {
iter: T,
n: uint
Expand Down Expand Up @@ -1615,6 +1628,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Skip<T> {

/// An iterator which only iterates over the first `n` iterations of `iter`.
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Take<T> {
iter: T,
n: uint
Expand Down Expand Up @@ -1664,6 +1678,7 @@ impl<A, T: RandomAccessIterator<A>> RandomAccessIterator<A> for Take<T> {


/// An iterator to maintain state while iterating another iterator
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Scan<'a, A, B, T, St> {
iter: T,
f: |&mut St, A|: 'a -> Option<B>,
Expand All @@ -1688,6 +1703,7 @@ impl<'a, A, B, T: Iterator<A>, St> Iterator<B> for Scan<'a, A, B, T, St> {
/// An iterator that maps each element to an iterator,
/// and yields the elements of the produced iterators
///
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct FlatMap<'a, A, T, U> {
iter: T,
f: |A|: 'a -> U,
Expand Down Expand Up @@ -1747,6 +1763,7 @@ impl<'a,
/// An iterator that yields `None` forever after the underlying iterator
/// yields `None` once.
#[deriving(Clone)]
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Fuse<T> {
iter: T,
done: bool
Expand Down Expand Up @@ -1819,6 +1836,7 @@ impl<T> Fuse<T> {

/// An iterator that calls a function with a reference to each
/// element before yielding it.
#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
pub struct Inspect<'a, A, T> {
iter: T,
f: |&A|: 'a
Expand Down Expand Up @@ -2298,4 +2316,3 @@ pub mod order {
}
}
}

5 comments on commit 27d18fb

@bors
Copy link
Contributor

@bors bors commented on 27d18fb Jul 10, 2014

Choose a reason for hiding this comment

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

saw approval from alexcrichton
at huonw@27d18fb

@bors
Copy link
Contributor

@bors bors commented on 27d18fb Jul 10, 2014

Choose a reason for hiding this comment

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

merging huonw/rust/must-use-iterators = 27d18fb into auto

@bors
Copy link
Contributor

@bors bors commented on 27d18fb Jul 10, 2014

Choose a reason for hiding this comment

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

huonw/rust/must-use-iterators = 27d18fb merged ok, testing candidate = 6372915

@bors
Copy link
Contributor

@bors bors commented on 27d18fb Jul 10, 2014

Choose a reason for hiding this comment

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

fast-forwarding master to auto = 6372915

Please sign in to comment.