# Using \{Blocks\} in Rust & Go for Fun & Profit Did you know you can just whip out curly-braces all over the place in Rust and Go? ```go a := 1 a = 2 { b := 1 } b := 2 ``` ```rust let mut a = 1; a = 2; { let b = 1; }; let b = 2; let c = { let mut d = 1; d = 2; d }; ``` But why on Earth would you even want to do this? --- ## Creating "Construction-Zones" When you're creating a variable that demands multiple initialization steps, it's tider to tuck the details into a block: ```rust // before let person = Person(id); person.authenticate(token).await; let raw_email = person.fetchEmail().await; let email = Email.parse(email); ``` ```rust // after let email = { let person = Person(id); person.authenticate(token).await; let raw_email = person.fetchEmail().await; Email.parse(email) } ``` In this example, it's obvious that the "end-goal" is `email`. At a quick-glance, you can see which variables are important, and which are intermediate ephemera. ## Containing Side-Effects and Error-Handling Every golang programmer knows the pain of juggling `result` and `err` variables. With blocks, you can tidily handle each `err` and other variables without worrying about weird assignment problems with `:=` and `=`: ```go id := 123 firstName := "John" lastName := "Smith" { result, err := db.Exec( `UPDATE usr SET first_name = $2 WHERE id = $1`, id, firstName, ) if result.RowsAffected() = 0 || err != nil { return err } } { result, err := db.Exec( `UPDATE usr SET last_name = $2 WHERE id = $1`, id, lastName, ) if result.RowsAffected() = 0 || err != nil { return err } } ``` ## Restricting Variable Lifetimes I like creating tidy "workspaces" for each group of intermediate variables: ```rust // define vars // do stuff with vars { // define intermediate vars // manipulate top-level vars } // do more stuff with vars { // define intermediate vars // manipulate top-level vars } // do even more stuff with vars ``` For example: ```go email := "j.smith@example.com" usr := Usr{} { var usrId int { err := db.QueryRow( `SELECT usr_id FROM usr_email WHERE email = $1`, email, ).Scan(&usrId) if err != nil { return err } } { err := db.QueryRow( `SELECT * FROM usr WHERE id = $1`, usrId, ).Scan(&usr) if err != nil { return err } } } ``` In this very contrived example, you can easily see the purpose of everything just by glancing at the general structure: - `email` is at the beginning with an explicit value, so it's a given input - `usr` is declared empty, so the block directly beneath it will define it - `usrId` is declared empty, so the block directly beneath it will define it - `usr` and `email` are the only variables that we need to care about after this section --- ## Conclusion Use `{}` blocks to prevent your variables from leaking everywhere. Your friends and coworkers will thank you.