Skip to content
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

iterator-related cleanup #8326

Merged
merged 7 commits into from
Aug 7, 2013
Merged

iterator-related cleanup #8326

merged 7 commits into from
Aug 7, 2013

Conversation

thestinger
Copy link
Contributor

The extra::iter module wasn't actually included in extra.rs when it was moved from std... I assume no one is going to miss it.

@bstrie
Copy link
Contributor

bstrie commented Aug 6, 2013

I'm obviously very much against removing .times(). The method is intended for dead-simple repetition, and to provide trivial examples of do notation, higher-order functions, and implementing methods on "builtin" types. It's great for tutorials and small examples. In short, it's good PR, and good PR is very important. for _ in range(0, x) is a poor replacement for these purposes. times is also 12 lines of code total: in other words, no maintenance burden whatsoever.

Constant allegations of cuteness aside, .times is found in hundreds of places thoughout the compiler. We'd always had the ability to write for range(0, x) |_| {, and yet people still elected to use .times instead. That alone should be evidence of its utility.

r- from me

@thestinger
Copy link
Contributor Author

I fully intend to support the same zero-parameter sugar in for loops as for iterator {} instead of for pattern in iterator {} for when pattern is _. It won't be any longer than do is with Times right now. You could consider this to a temporary bit of ugliness like advance was.

There's nothing to gain from having an alternate way of looping lacking a way to break and making you encounter closure capture errors. There is a cognitive overhead to have many different looping conventions in the standard library - Times doesn't even implement the old internal iterator protocol that's still cluttered around.

@alexcrichton
Copy link
Member

@thestinger, could times be modified to just return an iterator over () for now? That way once there's sugar for not capturing any patterns you'd still have the same syntax for 4.times { ... }? That would mean that all current users would be rewritten to for _ in 5.times {} which looks silly but it's on its way out.

@thestinger
Copy link
Contributor Author

@alexcrichton: yeah, it could just be a wrapper around range(start, stop) doing range(0, stop) but it would be a function rather than a method. It would be odd to stick a times method on anything implementing Add + Ord - Times isn't implemented generically and doesn't work on anything but uint (including unsigned big integers).

We used used to have a repeat internal iterator doing the same thing as Times, but repeat is going to repeat a value forever now.

I decided just to copy Python's convention for now because times(i) doesn't make sense in the way that i.times does.

@alexcrichton
Copy link
Member

I'm confused why this can't just be

pub trait Times {
    fn times(self) -> SomeIteratorOverUnit;
}

impl Times for uint {
    fn times(self) -> SomeIteratorOverUnit {
        range(0, self).transform(|_| ())
    }
}

@thestinger
Copy link
Contributor Author

@alexcrichton: As a function, it can be implemented once generically for all types. As a trait, it adds yet another numeric trait every unsigned numeric type will have to implement. You need an implementation for i8, i16, i32, i64, uint, unsigned big integers, and any alternate numeric types such as overflow-checked ones in the future.

If we use traits that way, they're actually doing the opposite of code reuse. There will be third-party numeric types, so it makes the language less friendly to them by increasing the size of a minimal implementation.

@thestinger
Copy link
Contributor Author

There's also no benefit from turning the result from an integer into (). It might as well just be a Range<T>.

@alexcrichton
Copy link
Member

I'm still confused what the problem is, if you want it generically why won't this work

impl<T: Required + Traits + For + Range> Times for T {
    fn times(self) -> SomeIteratorOverUnit {
        range(0, self)
    }
}

@thestinger
Copy link
Contributor Author

@alexcrichton: it will work, but if it's going to be in prelude it will reserve that name as a method (for types it can satisfy), which may not be wanted

@alexcrichton
Copy link
Member

I wouldn't necessarily be in favor of it being in the prelude. This is more of a "cute" language feature than something core which should be present in every module's namespace in my opinion.

@thestinger
Copy link
Contributor Author

I would really rather just have for range(0, n) { } as the one consistent way to do it.

to match the convention used by `range`, since `iterator::count` is
already namespaced enough and won't be ambiguous
This module provided adaptors for the old internal iterator protocol,
but they proved to be quite unreadable and are not generic enough to
handle borrowed pointers well.

Since Rust no longer defines an internal iteration protocol, I don't
think there's going to be any reuse via these adaptors.
This results in throwing away alias analysis information, because LLVM
does *not* implement reasoning about these conversions yet.

We specialize zero-size types since a `getelementptr` offset will
return us the same pointer, making it broken as a simple counter.
This allows LLVM to optimize vector iterators to an `getelementptr` and
`icmp` pair, instead of `getelementptr` and *two* comparisons.

Code snippet:

~~~
fn foo(xs: &mut [f64]) {
    for x in xs.mut_iter() {
        *x += 10.0;
    }
}
~~~

LLVM IR at stage0:

~~~
; Function Attrs: noinline uwtable
define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 {
"function top level":
  %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0
  %3 = load double** %2, align 8
  %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1
  %5 = load i64* %4, align 8
  %6 = ptrtoint double* %3 to i64
  %7 = and i64 %5, -8
  %8 = add i64 %7, %6
  %9 = inttoptr i64 %8 to double*
  %10 = icmp eq double* %3, %9
  %11 = icmp eq double* %3, null
  %or.cond6 = or i1 %10, %11
  br i1 %or.cond6, label %match_case, label %match_else

match_else:                                       ; preds = %"function top level", %match_else
  %12 = phi double* [ %13, %match_else ], [ %3, %"function top level" ]
  %13 = getelementptr double* %12, i64 1
  %14 = load double* %12, align 8
  %15 = fadd double %14, 1.000000e+01
  store double %15, double* %12, align 8
  %16 = icmp eq double* %13, %9
  %17 = icmp eq double* %13, null
  %or.cond = or i1 %16, %17
  br i1 %or.cond, label %match_case, label %match_else

match_case:                                       ; preds = %match_else, %"function top level"
  ret void
}
~~~

Optimized LLVM IR at stage1/stage2:

~~~
; Function Attrs: noinline uwtable
define void @"_ZN3foo17_68e1b25bca131dba7_0$x2e0E"({ i64, %tydesc*, i8*, i8*, i8 }* nocapture, { double*, i64 }* nocapture) #1 {
"function top level":
  %2 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 0
  %3 = load double** %2, align 8
  %4 = getelementptr inbounds { double*, i64 }* %1, i64 0, i32 1
  %5 = load i64* %4, align 8
  %6 = lshr i64 %5, 3
  %7 = getelementptr inbounds double* %3, i64 %6
  %8 = icmp eq i64 %6, 0
  %9 = icmp eq double* %3, null
  %or.cond6 = or i1 %8, %9
  br i1 %or.cond6, label %match_case, label %match_else

match_else:                                       ; preds = %"function top level", %match_else
  %.sroa.0.0.in7 = phi double* [ %10, %match_else ], [ %3, %"function top level" ]
  %10 = getelementptr inbounds double* %.sroa.0.0.in7, i64 1
  %11 = load double* %.sroa.0.0.in7, align 8
  %12 = fadd double %11, 1.000000e+01
  store double %12, double* %.sroa.0.0.in7, align 8
  %13 = icmp eq double* %10, %7
  br i1 %13, label %match_case, label %match_else

match_case:                                       ; preds = %match_else, %"function top level"
  ret void
}
~~~
@bstrie
Copy link
Contributor

bstrie commented Aug 7, 2013

I'm happy at the prospect of being able to omit the _ in, but using range(0, x) to repeat something x times still feels like a kludge to me (I'm aware that this is what Python does, and I still disapprove). It runs the risk of the same off-by-one errors that C's for is vulnerable to.

As for implementation, I really don't care. My only concern is the API. I agree that times(i) would be pointless, as one of the driving forces for the x.times approach was to avoid having to add a name to the universal namespace.

Honestly I don't care if it gets used in the compiler, so I'm still indifferent to the bulk of this PR. But I do insist that this API be made available, whether with for or do.

@bluss
Copy link
Member

bluss commented Aug 7, 2013

The main commit regarding Times is no longer in the PR, but there are a few times → range conversions in the commit "remove extra::iter"

@thestinger
Copy link
Contributor Author

I plan on opening the Times commit as a separate pull request. The compiler is not going to be using it regardless of any decision, because it's slow to compile closure-based loops.

An Iterator-based times would still be range, just behind a wrapper.

bors added a commit that referenced this pull request Aug 7, 2013
The `extra::iter` module wasn't actually included in `extra.rs` when it was moved from `std`... I assume no one is going to miss it.
@bors bors closed this Aug 7, 2013
@bors bors merged commit 55f3d04 into rust-lang:master Aug 7, 2013
@thestinger thestinger deleted the iterator branch August 7, 2013 21:03
flip1995 pushed a commit to flip1995/rust that referenced this pull request Feb 10, 2022
…xFrednet

warn if we find multiple clippy configs

Fixes rust-lang#8323

---

*Please write a short comment explaining your change (or "none" for internal only changes)*

changelog: warn if we find multiple clippy configs
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.

None yet

5 participants