News for hackers. Stuff that matters.
Re:Rust for C++ programmers – part 2: control flow by pcwalton on Sunday April 20, 2014 @03:54AM (#7616181)
enumerate() also has the advantage of guaranteed elimination of bounds checks. In general, iterators are Rust's solution for achieving C-like performance for common patterns with safety and without bounds checking.
Re:Rust for C++ programmers – part 2: control flow by masklinn on Sunday April 20, 2014 @03:58AM (#7616188)
That as well.

By the way, I always wonder: is there a reason for no Iterable trait, which for could just take directly and implicitly call `.iter()` on? E.g. why

    for e in my_vec.iter() {
but not

    for e in my_vec {

?
Re:Rust for C++ programmers – part 2: control flow by pcwalton on Sunday April 20, 2014 @03:59AM (#7616193)
You'd have to overload "for" to detect whether the expression implemented Iterable or Iterator to decide what to do, and that was felt to be too complex (e.g. what if you implement both?) There was an attempt to have a unified Iterable trait at one point [1], but I believe it didn't work with the trait matching rules.

[1]: https://github.com/mozilla/rust/issues/7597

Re:Rust for C++ programmers – part 2: control flow by masklinn on Sunday April 20, 2014 @04:07AM (#7616212)
> You'd have to overload "for" to detect whether the expression implemented Iterable or Iterator to decide what to do

Iterator implements Iterable as a trivial self-return (by default), and `for` only and always takes an Iterable?

> what if you implement both?

Depends what sort of weirdness you're trying to do I guess.

> I believe it didn't work with the trait matching rules.

Ah. Too bad.

Re:Rust for C++ programmers – part 2: control flow by pcwalton on Sunday April 20, 2014 @04:11AM (#7616216)
Yeah, I would rather have "for" defined only to operate on Iterables. If we modified the trait matching rules we could probably do that backwards compatibly post 1.0.
Re:Rust for C++ programmers – part 2: control flow by stormbrew on Sunday April 20, 2014 @05:23AM (#7616329)
Throwing some thoughts on this entire conversation from the perspective of someone who's been using C++ for a long time:

One of the reasons why the C++ for (:) syntax above feels like such an improvement over the traditional iterator for loop is that it cuts out a lot of noise that's the same for almost every container loop you ever do. The same objection could be raised as in another branch of this conversation, that you might have other kinds of ranges on an object, and I've even done that before (as obj.something_begin() and obj.something_end()). But even before ranged-for came it almost always turned out ugly and I regretted it.

If most uses of for in Rust call iter() (I don't know that they do, my experience with it thus far is really minimal, but it does seem common so far), it seems like a case where use should lead design and the extra noise cut out.

Basically, if I have more than one kind of range on an object I'd probably rather have functions on the object that return the 'unusual' ranges for the iteration. So rather than having:

    for i in obj.iter() # the normal thing that I use all the time
    for i in obj.bfs_iter() # something I use sometimes to be more explicit
    for i in obj.dfs_iter() # another thing I use sometimes
I'd rather have:

    for i in obj # the normal thing that I use all the time
    for i in obj.breadth_first() # something I use sometimes to be more explicit
    for i in obj.depth_first() # another thing I use sometimes
Or if there is no sensible default, to be forced to name the thing I actually need.

It seems entirely sensible to me to expect the for loop construct to take an Iterable object. It actually makes more sense to me than for it to take an iterator directly, conceptually.

On the question of 'what if both?' I'd propose making it so hard (or impossible?) to do that. If for took Iterable, and Iterators also implemented Iterable as "return this", there'd really be no concept of having both (except in that if you have an iterator, it is always both) and for itself would be left fairly uncomplicated while still being able to take both Iterable and Iterator objects.

I'm probably missing some reason why this isn't an obvious way to go, as a definite Rust newb, but it would feel natural to (my C++-rotted perhaps) brain. Also I know there's no language changes until post-1.0, so for now it is what it is.

[edit] Huh. Ok, re-reading it looks like this was almost all covered ground. Never mind.