
Rust for C++ programmers – part 2: control flow - pohl
http://featherweightmusings.blogspot.com/2014/04/rust-for-c-programmers-part-2-control.html
======
masklinn
> If we want to index over the indices of `all` (a bit more like a standard
> C++ for loop over an array), you could do
    
    
        for i in range(0, all.len()) {
            println!("{}: {}", i, all.get(i));
        }
    

I'd suggest using `enumerate`[0] instead of creating a range on an existing
collection:

    
    
        for (i, n) in all.iter().enumerate() {
            println!("{}: {}", i, n);
        }
    

[0] [http://static.rust-
lang.org/doc/0.10/std/iter/struct.Enumera...](http://static.rust-
lang.org/doc/0.10/std/iter/struct.Enumerate.html#method.enumerate)

~~~
acqq
I have rather questions like: Why all.inter().enumerate() and not just
all.enumerate() ? Why for a in all.iter() and not simply for a in all ?

Apparently is the language clever enough to match the types (which is good),
why isn't than simply clever enough to recognize then that in on the array
needs the iteration? Why isn't possible to directly enumerate the array?

Even (at least this one) C++ has something simple:

[http://msdn.microsoft.com/en-
us/library/jj203382.aspx](http://msdn.microsoft.com/en-
us/library/jj203382.aspx)

    
    
        for( auto y : x ) { // Copy of 'x', almost always undesirable
            cout << y << " ";
        }
    
        for( auto &y : x ) { // Type inference by reference.
            // Observes and/or modifies in-place. Preferred when modify is needed.
            cout << y << " ";
        }
    
        for( const auto &y : x ) { // Type inference by reference.
            // Observes in-place. Preferred when no modify is needed.
    

Not even "in" keyword is used there but it still allows iterations through
anything that can be iterated without writing too much red tape, by invisibly
expanding to these famous STL declare iterator with the unnecessary long
declaration, iterate between begin and end constructs:

    
    
        range-based for: 
         Automatically recognizes arrays.
         Recognizes containers that have .begin() and .end().
         Uses argument-dependent lookup begin() and end() for anything else

~~~
masklinn
> Why all.iter().enumerate() and not just all.enumerate() ?

enumerate is a method of the Iterator trait, so you need an iterator. This way
it can have a truckload of reusable methods without polluting every
collection's namespace I guess, and still things work for collections with
multiple iterators (just ask for the right one).

The iteration method does not have to be called ``iter`` I'd think (e.g. a
tree structure might provide both a depth-first and a breadth-first iterator,
none of which would be accessed via `iter`?)

~~~
acqq
I'd do:

    
    
        for x in all     does .iter()
        for (x,y) in all.enumerate()   does .iter.enumerate()
    

And were there's no one iter() like trees, only by them it would have to be
specified, as they wouldn't have iter():

    
    
        for x in all.depthfirstiter()
        for (x,y) in all.depthfirstiter().enumerate()
    

95% of times 5% percent of the constructs are used, why not making them
pleasant?

~~~
masklinn
> I'd do: for x in all does .iter()

See pcwalton's answer in an other subthread, an Iterable trait (which for
would use instead of Iterator) was tried and didn't work out previously, but
it's not shelved.

> for (x,y) in all.enumerate() does .iter.enumerate()

That makes literally no sense. What if enumerate() is the thing returning an
iterable because reasons? Now it calls enumerate() on the wrong object, or
blows up because there's no .iter in the first place.

You _could_ have 30 methods on the Iterable trait (or directly on your vector)
which would just delegate to the corresponding Iterator. Not sure there's that
much value in it.

> for x in all.depthfirstiter()

Except according to your previous declaration that would result in a call to
`all.iter.depthfirstiter()`. Or the compiler has to go magic things around,
traverse the chain until it gets the first (or last? Or all of them? How do
you pick which one's right?) Iterable, an inject an iter() calls in it…

------
shmerl
What is the reason for using overly minimalistic, assembly style keywords like
fn, str etc? Even C++ doesn't go that far (I think string is more pleasant to
read than str). It's not like it's saving much, and it only worsens
readability.

~~~
jfager
It's a matter of taste. I personally feel that your specific examples make
Rust more readable, because of how little space gets wasted on those frequent,
unambiguous names. Ubiquitous boilerplete-ish things that show up everywhere
_should_ recede a bit, imo; let me spend my line width budget on what's unique
and important about my code.

But again, it's just a matter of taste and not really worth wasting a lot of
time worrying about. The important thing about Rust is its semantics (speed,
safety, control), not its syntax.

~~~
bjz_
> The important thing about Rust is its semantics (speed, safety, control),
> not its syntax.

Agreed. I love Haskell syntax above all else, but I like Rust's semantics too
much to let that get in the way of me using it.

------
acqq
I still find it's a pity that so new language has "you must write let" that
even Basic programmers don't have to do during at least 30-40 years:

[https://www.powerbasic.com/support/help/pbcc/let_statement.h...](https://www.powerbasic.com/support/help/pbcc/let_statement.htm)

I remember not having to write let in Basic even in eighties. Anyway, since
1995,
[http://en.wikipedia.org/wiki/Limbo_(programming_language)](http://en.wikipedia.org/wiki/Limbo_\(programming_language\))
people have an idea that there is a simple way to have "define and assign"
that is different from "assign" without requiring a keyword: use := for define
and assign, x:=exp is equivalent to let x=exp, use = for just assign. Google
Go just reused that idea. Even if it's used today by Go, I still don't
understand why Rust avoids it, because it makes sources significantly more
readable: the variable is not obstructed by the keyword.

let mut is even more "stuff" before the variable in the language where
declarations otherwise always follow the variable (which is good!) I'd use x
:= expression and x : mut = expression.

~~~
pcwalton
It wouldn't work in Rust because "let" supports arbitrary (irrefutable)
patterns, and Rust has full pattern matching. The parser has to know when a
pattern is coming up. Languages that use :=, like Go, don't have a complete
set of destructuring features. The convenience of being able to have an
arbitrary pattern in "let" bindings far outweighs the disadvantage of having
to type "let".

"x : mut = expression" wouldn't work in Rust because types follow :, and "mut"
is not part of a type. "mut" is needed after each binding because one pattern
can contain some mutable bindings and some immutable bindings.

~~~
jnbiche
As someone who is learning OCaml at the same time as Rust (and who already had
some Haskell), I can attest that the power of pattern matching is well-worth
the extra "let". Plus, in addition to the signal it provides to the compiler,
it also provides _me_ a signal to know that I've got a new variable and the
option here to do destructuring pattern matching. Very cool.

pcwalton: after getting over the hump of Rust's pointer semantics, I've found
that it's a very elegant and fairly simple language. So I was partially wrong
about my assessment of Rust as a "complex" language (I say "partially" because
the pointer semantics do add a significant layer of unavoidable complexity).

I'd encourage anyone put off by the complexity of Rust's pointers to just push
on through. I think you'll find it's worth the trouble.

Rust is definitely _the_ language of the future for games, embedded
programming, system programming and other areas of programming that require a
high level of determinism. I can't wait until it's stable enough to use for
real projects (hopefully sometime this year).

~~~
steveklabnik
Have you read [http://static.rust-lang.org/doc/master/guide-
pointers.html](http://static.rust-lang.org/doc/master/guide-pointers.html) ?

~~~
jnbiche
Yes. That was the guide, along with the pointer semantics table, that
basically convinced me to give Rust a second chance, since if pointers could
be summed up in a table, they were definitely comprehensible even for a PL
peon like me.

~~~
steveklabnik
Cool, thank you. I was wondering if it helped or hurt. Great!

------
logicchains
Why is the symbol '|' used for or in pattern matching, not '||'? If '|' is
used for bitwise or elsewhere in the language then this might lead to
confusion.

~~~
masklinn
> If '|' is used for bitwise or elsewhere in the language then this might lead
> to confusion.

`||` is the logical or[0], why would it lead to less confusion?

(and yes, `|` is the bitwise or[1])

[0] [http://static.rust-lang.org/doc/0.10/rust.html#lazy-
boolean-...](http://static.rust-lang.org/doc/0.10/rust.html#lazy-boolean-
operators)

[1] [http://static.rust-lang.org/doc/0.10/rust.html#bitwise-
opera...](http://static.rust-lang.org/doc/0.10/rust.html#bitwise-operators)

~~~
logicchains
I suppose I just assumed that logical or is closer in meaning to the or in
pattern matching than bitwise or is.

------
jhgg
What's the purpose of:

    
    
        y if y < 20
    

In the match block, can't we just use x?

~~~
masklinn
Yes, you could write this as `_ if x < 20`. But not as `if x < 20`, I'm pretty
sure the pattern is mandatory.

------
dcsommer
Another great entry. Keep 'em coming!

------
xixixao
The two issues in the comments so far, iteration with index variable and
assignment/destructuring without explicit let are both handled beautifully by
CoffeeScript. At least Rust gets right "everything is an expression". One of
the best things CoffeeScript "brought".

~~~
cmrx64
As if coffeescript originated the features... We don't have iteration with
index variable because it's seen as extraneous and unnecessary. If you aren't
using iterators, you're paying for unnecessary bounds checks (LLVM often can't
optimize them out). The explicit let mostly comes from the ML heritage and
want for nice pattern matching.

