Question on last sentence on page 44 print edition of Begin Rust, please :)

4 views
Skip to first unread message

NoOne OfConsequence

unread,
Jun 21, 2021, 11:43:42 AMJun 21
to Begin Rust
Question on this (section 3.5) page 44 sentence, please: "That block automatically gets everything from the parent scope."

Is the sentence true for blocks that are function bodies?

I modified the code on page 44, adding a let statement and a nested function:
fn say_apples (apples:i32) {
    println!(" {}", apples);

    let oranges = 2;
    fn wont_compile() -> i32 {
        apples + oranges
    }
}
fn main() {
    say_apples(10);
    //println!("apples == {}", apples);
}

The function wont_compile() gets 2 occurrences of 
----> error[E0434]: can't capture dynamic environment in a fn item <----
once for apples, once for oranges.

I don't mean to force my opinion on you or others who read this post. That said, I really, really like error E0434. It forces Rust programmers to put all named values such as apples/oranges in the function's parameter list. And since we only write short functions, that means when the function's source code is re-read, re-read, and re-read again during maintenance, the total life-cycle cost of writing once and re-reading many times is lower, because all the names the re-reading coders might wonder about are *right there* in the parameter list.

I'm pretty new to Rust. Have I misunderstood about error E0434?

ps - Really enjoying the book. Retired software engineer looking at books to use to teach coding to grandchildren when they get older.





Michael Snoyman

unread,
Jun 21, 2021, 1:36:05 PMJun 21
to Begin Rust


On Mon, Jun 21, 2021, at 6:43 PM, NoOne OfConsequence wrote:
Question on this (section 3.5) page 44 sentence, please: "That block automatically gets everything from the parent scope."

Is the sentence true for blocks that are function bodies?

No, function items use block-like structures for their bodies, but are not "vanilla" blocks and have their own scoping rules. We don't get into the details of this in the book, but closures allow you to capture variables in a function-like construct. This is a more advanced reference than the book, but given your closing comments I think you may be interested in looking at the Rust reference on functions and closures:


I modified the code on page 44, adding a let statement and a nested function:
fn say_apples (apples:i32) {
    println!(" {}", apples);

    let oranges = 2;
    fn wont_compile() -> i32 {
        apples + oranges
    }
}
fn main() {
    say_apples(10);
    //println!("apples == {}", apples);
}

The function wont_compile() gets 2 occurrences of 
----> error[E0434]: can't capture dynamic environment in a fn item <----
once for apples, once for oranges.

I don't mean to force my opinion on you or others who read this post. That said, I really, really like error E0434. It forces Rust programmers to put all named values such as apples/oranges in the function's parameter list. And since we only write short functions, that means when the function's source code is re-read, re-read, and re-read again during maintenance, the total life-cycle cost of writing once and re-reading many times is lower, because all the names the re-reading coders might wonder about are *right there* in the parameter list.

I'm pretty new to Rust. Have I misunderstood about error E0434?

I'm not sure if you've misunderstood it, but I don't think it's intended to imply anything widescale about the size of functions or application design. fn items (actual functions) have a specific limitation: they cannot capture variables. There is very good reason for this: capturing variables leads to a lot of complexity in general, and especially so with a language including ownership and borrow checking. It's a large part of why we decided to not include closures in Begin Rust: it's a more advanced topic.

Just for comparison's sake, however, here's a "fixed" version of your code using closures which does compile:

```
fn say_apples(apples: i32) {
    println!(" {}", apples);

    let oranges = 2;
    let will_compile = || -> i32 { apples + oranges };

    println!("Result: {}", will_compile());
}

fn main() {
    say_apples(10);
    //println!("apples == {}", apples);
}
```

ps - Really enjoying the book. Retired software engineer looking at books to use to teach coding to grandchildren when they get older.




Thank you! I'm interested to hear how it goes teaching your grandchildren, if you're up for sharing the experience.



--
You received this message because you are subscribed to the Google Groups "Begin Rust" group.
To unsubscribe from this group and stop receiving emails from it, send an email to begin-rust+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages