Why does shadowing change the mutability of a variable in this code? - rust

In thie following code,
fn main()
{
let mename : String = String::from("StealthyPanda");
println!("{mename}");
let mename = displayswithhere(mename);
println!("{mename}");
let mename = addshere(mename);
println!("{mename}");
}
fn displayswithhere(astring: String) -> String
{
println!("{astring} here!");
return astring;
}
fn addshere(mut astring : String) -> String
{
astring.push_str(" here!");
astring
}
Why isn't there an error after mename is shadowed and not declared as mutable when being assigned the value of displayswithhere(mename)? The code runs exactly as if the variable mename was mutable all along. I don't understand where the bug in the code, if any, is located.

When you shadow a variable, you create another one, distinct from the previous, but with the same name (that is just a coincidence).
The drawback is that you cannot simply refer to the former with its name any more because this names now refers to the latter.
On the example below, the functions fn_1() and fn_2() are very similar except that in fn_1() we still can refer directly to the original variable, but in fn_2() we have to find another way: we introduce a reference with a different name.
This is not related to mutability since the original variable keeps its original value all the way long.
On the other hand, fn_3() relies on mutability but we do not use let with the same name a second time, so the second assign operation is not an initialisation of a new variable but a real assign operation which will change the value of the original variable.
fn fn_1() {
println!("~~~~~~~~");
let my_var = 1;
println!("my_var: {}", my_var);
let my_other_var = 2; // creating another variable with a different name
println!("my_other_var: {}", my_other_var);
println!("my_var: {}", my_var);
}
fn fn_2() {
println!("~~~~~~~~");
let my_var = 1;
println!("my_var: {}", my_var);
let ref_to_my_var = &my_var;
let my_var = 2; // creating another variable with the same name (coincidence)
println!("my_var: {}", my_var);
println!("ref_to_my_var: {}", ref_to_my_var);
}
fn fn_3() {
println!("~~~~~~~~");
let mut my_var = 1;
println!("my_var: {}", my_var);
my_var = 2; // changing the origianl variable, which must be mutable
println!("my_var: {}", my_var);
}
fn main() {
fn_1();
fn_2();
fn_3();
}
/*
~~~~~~~~
my_var: 1
my_other_var: 2
my_var: 1
~~~~~~~~
my_var: 1
my_var: 2
ref_to_my_var: 1
~~~~~~~~
my_var: 1
my_var: 2
*/

You're saying "the variable mename", but there's three in your main function. You can convince yourself of that by running the following code:
#![allow(unused_variables)]
struct Foo(i32);
impl Foo {
fn new(v: i32) -> Foo {
println!("{v}");
Foo(v)
}
}
impl Drop for Foo {
fn drop(&mut self) {
println!("{}", self.0);
}
}
fn main() {
let foo = Foo::new(0);
let foo = Foo::new(1);
let foo = Foo::new(2);
println!("At this point, all three Foos are alive, each in its own variable");
}
Now you may ask, if I can just shadow a previous variable, what's the difference to just having it mutable? The difference should become apparent when your run this code:
fn main() {
let i = 0;
for _ in 0..2 {
println!("{i}");
let i = i + 1;
println!("{i}");
}
}

Related

I dont understand this lifetime error : spawining threads inside a struct function

Not much to explain. I don't understand what is even having the lifetime designated 1 and 2 by the compiler error message.
All posts I have checked so far just say use crossbeam for scopped threads, but this hasn't fixed my issue at all and I dont think I even understand the finer issue here.
Any help is appreciated.
use crossbeam_utils::thread;
struct TestStruct {
s: f64,
}
impl TestStruct {
fn new() -> Self {
Self {
s: -1.,
}
}
fn fubar(&'static self) -> f64 {
let thread_return_value = thread::scope(|scope|
// lifetime may not live long enough
// returning this value requires that `'1` must outlive `'2`
// Question: what are the two lifetimes even of? I am probably just
// a noob here.
scope.spawn(move |_| { // same error with or without move
// I have found that it doesnt matter what I put in this scope,
// but the following is the closest to what I have in my actual
// code.
let mut psum = 0.;
for _ in 0..10 { psum += self.s; }
psum
})
).unwrap();
// do anything with thread_return_value
return 0.; // just so its explicitly not the problem here, return 0.
}
}
fn main() {
let test_item = TestStruct::new();
// rustcE0597
let stored_value = test_item.fubar();
println!("{}", &stored_value);
return;
}
Edit after marking for correct answer, working minimal example:
#![feature(let_chains)]
use crossbeam_utils::thread;
struct TestStruct {
s: f64,
}
impl TestStruct {
fn new() -> Self {
Self {
s: -1.,
}
}
fn fubar(&self) -> f64 {
let thread_return_value = thread::scope(|scope| {
let th = scope.spawn(move |_| {
let mut psum = 0.;
for _ in 0..10 { psum += self.s; }
psum
});
let psum = th.join().unwrap();
psum
}
).unwrap();
return thread_return_value;
}
}
fn main() {
let test_item = TestStruct::new();
// rustcE0597
let stored_value = test_item.fubar();
println!("{}", &stored_value);
return;
}
The most obvious problem in your code is the &'static self lifetime. If you do so, you will only be able to call this function with static (that is, global) values of this type. So just remove that 'static and write &self.
Then the real problem is because you are trying to return your scoped thread handle from the crossbeam::scoped, the value returned by scope.spawn(), and that is not allowed. That is why they are called scoped threads: they are limited to the enclosing scope.
Remember that in Rust, when a block ends without a ; the value of the last expression is returned as the value of the block itself.
You probably want to return the psum. If so you need to wait for the handle to finish:
fn fubar(& self) -> f64 {
let thread_return_value = thread::scope(|scope| {
let th = scope.spawn(move |_| {
let mut psum = 0.;
for _ in 0..10 { psum += self.s; }
psum
}); // <--- here, add a ;
let psum = th.join().unwrap(); //get the inner result
psum //forward it to the outer scope
}).unwrap();
return 0.;
}

Dealing with so-called global variables in Rust

We all know that using global variables can lead to subtle bugs. I need to migrate Python programs to Rust, keeping the algorithm intact as far as possible. Once I have demonstrated Python-Rust equivalence there will be opportunities to debug and change the logic to fit Rust better. Here is a simple Python program using global variables, followed by my unsuccessful Rust version.
# global variable
a = 15
# function to perform addition
def add():
global a
a += 100
# function to perform subtraction
def subtract():
global a
a -= 100
# Using a global through functions
print("Initial value of a = ", a)
add()
print("a after addition = ", a)
subtract()
print("a after subtraction = ", a)
Here is a Rust program that runs, but I cannot get the closures to update the so-called global variable.
fn fmain() {
// global variable
let mut a = 15;
// perform addition
let add = || {
let mut _name = a;
// name += 100; // the program won't compile if this is uncommented
};
call_once(add);
// perform subtraction
let subtract = || {
let mut _name = a;
// name -= 100; // the program won't compile if this is uncommented
};
call_once(subtract);
// Using a global through functions
println!("Initial value of a = {}", a);
add();
println!("a after addition = {}", a);
subtract();
println!("a after subtraction = {}", a);
}
fn main() {
fmain();
}
fn call_once<F>(f: F)
where
F: FnOnce(),
{
f();
}
My request: Re-create the Python logic in Rust.
Your Rust code is not using global variables, the a variable is stack-allocated. While Rust doesn't particularly endorse global variables, you can certainly use them. Translated to Rust that uses actual globals, your program would look like this:
use lazy_static::lazy_static;
use parking_lot::Mutex; // or std::sync::Mutex
// global variable
lazy_static! {
static ref A: Mutex<u32> = Mutex::new(15);
}
// function to perform addition
fn add() {
*A.lock() += 100;
}
// function to perform subtraction
fn subtract() {
*A.lock() -= 100;
}
fn main() {
// Using a global through functions
println!("Initial value of a = {}", A.lock());
add();
println!("a after addition = {}", A.lock());
subtract();
println!("a after subtraction = {}", A.lock());
}
Playground
If you prefer to use closures, you can do that too, but you'll need to use interior mutability to allow multiple closures to capture the same environment. For example, you could use a Cell:
use std::cell::Cell;
fn main() {
let a = Cell::new(15);
let add = || {
a.set(a.get() + 100);
};
let subtract = || {
a.set(a.get() - 100);
};
// Using a global through functions
println!("Initial value of a = {}", a.get());
add();
println!("a after addition = {}", a.get());
subtract();
println!("a after subtraction = {}", a.get());
}
Playground
Dependency-less examples as enum and function. EDIT : Code improved, as suggested in comment and corrected match arm.
use std::sync::{Arc, Mutex, Once};
static START: Once = Once::new();
static mut ARCMUT: Vec<Arc<Mutex<i32>>> = Vec::new();
// as enum
enum Operation {
Add,
Subtract,
}
impl Operation {
// static change
fn result(self) -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlock = arc_clone.lock().unwrap();
match self {
Operation::Add => *unlock += 100,
Operation::Subtract => *unlock -= 100,
}
*unlock
}
// dynamic change
fn amount(self, amount: i32) -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlock = arc_clone.lock().unwrap();
match self {
Operation::Add => *unlock += amount,
Operation::Subtract => *unlock -= amount,
}
*unlock
}
}
// as a function
fn add() -> i32 {
let mut arc_clone = unsafe { ARCMUT[0].clone() };
let mut unlcok = arc_clone.lock().unwrap();
*unlcok += 100;
*unlcok
}
// as trait
trait OperationTrait {
fn add(self) -> Self;
fn subtract(self) -> Self;
fn return_value(self) ->i32;
}
impl OperationTrait for i32 {
fn add(mut self) -> Self {
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock += self;
self
}
fn subtract(mut self) -> Self {
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock -= self;
self
}
fn return_value(self)->Self{
let arc_clone = unsafe{ARCMUT[0].clone()};
let mut unlock = arc_clone.lock().unwrap();
*unlock
}
}
// fn main
fn main() {
START.call_once(|| unsafe {
ARCMUT = vec![Arc::new(Mutex::new(15))];
});
let test = Operation::Add.result();
println!("{:?}", test);
let test = Operation::Subtract.amount(100);
println!("{:?}", test);
let test = add();
println!("{:?}", test);
let test = 4000.add();
println!("{:?}", test);
}

`while let Ok(t) ... = try_read!(...)` to make neater reading loop

Is it possible to make short, neat loop that will call , as long as result is Ok(x) and act on x ?
E.g. sth like :
use text_io::try_read; // Cargo.toml += text_io = "0.1"
fn main() {
while let Ok(t): Result<i64, _> = try_read!() {
println!("{}", t);
}
}
fails to compile.
If I try to provide type info, then it fails,
when I don't provide , then obviously it's ambiguous how to resolve try_read!.
Here is working - but IMHO way longer - snippet:
use text_io::try_read; // Cargo.toml += text_io = "0.1"
fn main() {
loop {
let mut tok: Result<i64, _> = try_read!();
match tok {
Ok(t) => println!("{}", t),
Err(_) => break,
}
}
}
You can qualify Ok as Result::Ok and then use the "turbofish" operator to provide the concrete type:
fn main() {
while let Result::<i64, _>::Ok(t) = try_read!() {
println!("{}", t);
}
}
(while let Ok::<i64, _>(t) also works, but is perhaps a bit more cryptic.)
Another option is to request the type inside the loop - rustc is smart enough to infer the type for try_read!() from that:
fn main() {
while let Ok(t) = try_read!() {
let t: i64 = t;
println!("{}", t);
}
}
The latter variant is particularly useful in for loops where the pattern match is partly hidden, so there is no place to ascribe the type to.

How to use an input argument as the name of a created variable?

So basically I would have a function that asks for two input arguments, call it name and value. Now the value x is fed into name and I want it so that a new variable called x comes up assigned with the value inside "value"
I tried it by just doing name = value but that ends up reassigning the value inside name to be value from x and not reassigning x to be value.
pub fn main()
{
variable_maker(x, 20)
}
pub fn variable_maker(name, value)
{
name = value;
}
Only a macro:
macro_rules! variable_maker {
($name:ident, $expression:expr) => {
let mut $name = $expression;
};
}
fn main() {
variable_maker!(x, 20);
println!("{}", x); // 20
x = 30;
println!("{}", x); // 30
}
But what's the point?

How can I set a struct field value by string name?

Out of habit from interpreted programming languages, I want to rewrite many values based on their key. I assumed that I would store all the information in the struct prepared for this project. So I started iterating:
struct Container {
x: String,
y: String,
z: String
}
impl Container {
// (...)
fn load_data(&self, data: &HashMap<String, String>) {
let valid_keys = vec_of_strings![ // It's simple vector with Strings
"x", "y", "z"
] ;
for key_name in &valid_keys {
if data.contains_key(key_name) {
self[key_name] = Some(data.get(key_name);
// It's invalid of course but
// I do not know how to write it correctly.
// For example, in PHP I would write it like this:
// $this[$key_name] = $data[$key_name];
}
}
}
// (...)
}
Maybe macros? I tried to use them. key_name is always interpreted as it is, I cannot get value of key_name instead.
How can I do this without repeating the code for each value?
With macros, I always advocate starting from the direct code, then seeing what duplication there is. In this case, we'd start with
fn load_data(&mut self, data: &HashMap<String, String>) {
if let Some(v) = data.get("x") {
self.x = v.clone();
}
if let Some(v) = data.get("y") {
self.y = v.clone();
}
if let Some(v) = data.get("z") {
self.z = v.clone();
}
}
Note the number of differences:
The struct must take &mut self.
It's inefficient to check if a value is there and then get it separately.
We need to clone the value because we only only have a reference.
We cannot store an Option in a String.
Once you have your code working, you can see how to abstract things. Always start by trying to use "lighter" abstractions (functions, traits, etc.). Only after exhausting that, I'd start bringing in macros. Let's start by using stringify
if let Some(v) = data.get(stringify!(x)) {
self.x = v.clone();
}
Then you can extract out a macro:
macro_rules! thing {
($this: ident, $data: ident, $($name: ident),+) => {
$(
if let Some(v) = $data.get(stringify!($name)) {
$this.$name = v.clone();
}
)+
};
}
impl Container {
fn load_data(&mut self, data: &HashMap<String, String>) {
thing!(self, data, x, y, z);
}
}
fn main() {
let mut c = Container::default();
let d: HashMap<_, _> = vec![("x".into(), "alpha".into())].into_iter().collect();
c.load_data(&d);
println!("{:?}", c);
}
Full disclosure: I don't think this is a good idea.

Resources