In Rust, what's the difference between "shadowing" and "mutability"? - variables

In Chapter 3 of the Rust Book, Variables and Mutability, we go through a couple iterations on this theme in order to demonstrate the default, immutable behavior of variables in Rust:
fn main() {
let x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
Which outputs:
error[E0384]: cannot assign twice to immutable variable `x`
--> src/main.rs:4:5
|
2 | let x = 5;
| -
| |
| first assignment to `x`
| help: make this binding mutable: `mut x`
3 | println!("The value of x is {}", x);
4 | x = 6;
| ^^^^^ cannot assign twice to immutable variable
However, because of Rust's take on shadowing variables, we can simply do this to change the value of the nonetheless "immutable" x:
fn main() {
let x = 5;
println!("The value of x is {}", x);
let x = 6;
println!("The value of x is {}", x);
}
Which outputs (skipping the details):
The value of x is 5
The value of x is 6
Funnily enough, this code also produces the above pair of lines as output, despite the fact that we don't call let but instead mut the first time x is bound to 5:
fn main() {
let mut x = 5;
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
This ambiguity in how variables are (not really) protected from reassignment seems contrary to the stated goal of protecting the values bound to immutable - by Rust default - variables. From the same chapter (which also contains the section Shadowing):
It’s important that we get compile-time errors when we attempt to
change a value that we previously designated as immutable because this
very situation can lead to bugs. If one part of our code operates on
the assumption that a value will never change and another part of our
code changes that value, it’s possible that the first part of the code
won’t do what it was designed to do. The cause of this kind of bug can
be difficult to track down after the fact, especially when the second
piece of code changes the value only sometimes.
In Rust, the compiler guarantees that when you state that a value
won’t change, it really won’t change. That means that when you’re
reading and writing code, you don’t have to keep track of how and
where a value might change. Your code is thus easier to reason
through.
If I can cause this important feature of my immutable x to be side-stepped with an innocent enough call to let, why do I need mut? Is there some way to really, seriously-you-guys make x immutable, such that no let x can reassign its value?

I believe the confusion is because you're conflating names with storage.
fn main() {
let x = 5; // x_0
println!("The value of x is {}", x);
let x = 6; // x_1
println!("The value of x is {}", x);
}
In this example, there is one name (x), and two storage locations (x_0 and x_1). The second let is simply re-binding the name x to refer to storage location x_1. The x_0 storage location is entirely unaffected.
fn main() {
let mut x = 5; // x_0
println!("The value of x is {}", x);
x = 6;
println!("The value of x is {}", x);
}
In this example, there is one name (x), and one storage location (x_0). The x = 6 assignment is directly changing the bits of storage location x_0.
You might argue that these do the same thing. If so, you would be wrong:
fn main() {
let x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
let x = 6; // x_1
println!("The value of y is {}", y);
}
This outputs:
The value of y is 5
The value of y is 5
This is because changing which storage location x refers to has absolutely no effect on the storage location x_0, which is what y_0 contains a pointer to. However,
fn main() {
let mut x = 5; // x_0
let y = &x; // y_0
println!("The value of y is {}", y);
x = 6;
println!("The value of y is {}", y);
}
This fails to compile because you cannot mutate x_0 while it is borrowed.
Rust cares about protecting against unwanted mutation effects as observed through references. This doesn't conflict with allowing shadowing, because you're not changing values when you shadow, you're just changing what a particular name means in a way that cannot be observed anywhere else. Shadowing is a strictly local change.
So yes, you absolutely can keep the value of x from being changed. What you can't do is keep what the name x refers to from being changed. At most, you can use something like clippy to deny shadowing as a lint.

Related

How to do multiple variable assignments in one line in Kotlin like C,C++?

I had to swap 2 numbers in one line expression using no other variable except x and y.
So I wrote the following .c program to swapp two numbers with the given conditions and it works like charm.
int main() {
int x =5, y =2;
x = y-x+(y=x);
printf("X=%d, y=%d", x, y);
return 0;
}
But when i try to do the same in kotlin it gives me an error that
Assignments are not expressions, and only expressions are allowed in
this context,
I can resolve this issue by introducing a third variable just like this. But I'm not allowed to have any other variable except x and y which are already given. So is there any other way I can do this in one line using any kotlin property?
Below is the kotlin program
fun main() {
var x = 5
var y = 10
x = y-x+(y=x)
println("X = $x, Y = $y")
}
While I have two suggestions below, I want to start with a recommendation against either of them, at least in this simple example.
It's usually a lot more clear to optimise code for developers to read in the following ways:
create an extra variable with a descriptive name
prefer val over var to avoid accidental mutations
and try to make the code 'linear', so the operations can be read from top-to-bottom without jumping between functions
avoid code that needs an IDE to see what the type-hints are
And I'll trust that the compiler will make make the code performant.
fun main() {
val x = 5
val y = 10
val newX = y
val newY = x
println("X = $newX, Y = $newY")
}
Local function
You could use a local function to perform the swap, as the function will still be able to access the original values.
fun main() {
var x = 5
var y = 10
fun swap(originalX: Int, originalY: Int) {
y = originalX
x = originalY
}
swap(x, y)
println("X = $x, Y = $y")
}
Scope function
This could be code-golfed into one line
use to to create a Pair<Int, Int>,
and a scope function to use the result.
fun main() {
var x = 5
var y = 10
(x to y).apply { x = second; y = first }
println("X = $x, Y = $y")
}
One line? Yes. More difficult to read? I think so.

How do I iterate over the elements of a finite set object in Dafny?

What is the best way to iterate over the elements of a finite set object in Dafny? An example of working code would be delightful.
This answer explains how to do it using a while loop, rather than by defining an iterator. The trick is to use the "assign such that" operator,
:|, to obtain a value y such that that y is in the set, and then repeat on that set with the y removing, continuing until there are not more elements. The decreases clause is necessary here. With it, Dafny proves termination of the while loop, but without it, not.
method Main()
{
var x: set<int> := {1, 2, 3};
var c := x;
while ( c != {} )
decreases c;
{
var y :| y in c;
print y, ", ";
c := c - { y };
}
}

Why doesn't the compiler report an error when a variable not declared as mutable is modified?

I installed Rust 1.13 and tried:
fn main() {
let x: u32;
x = 10; // no error?
}
When I compiled this file there's some warnings, but there's no error. As I'm not declaring x as mut, shouldn't x = 10; cause an error?
What you have written is identical to:
let x: u32 = 10;
The compiler will not permit you to mutate it thereafter:
let x: u32;
x = 10;
x = 0; // Error: re-assignment of immutable variable `x`
Note that it is a compiler error if you try to use an uninitialized variable:
let x: u32;
println!("{}", x); // Error: use of possibly uninitialized variable: `x`
This feature can be pretty useful if you want to initialize the variable differently based on runtime conditions. A naive example:
let x: u32;
if condition {
x = 1;
} else if other_condition {
x = 10;
} else {
x = 100;
}
But still it will still be an error if there is a possibility that it isn't initialized:
let x: u32;
if condition {
x = 1;
} else if other_condition {
x = 10;
} // no else
println!("{:?}", x); // Error: use of possibly uninitialized variable: `x`
As mentioned, this is not mutation, but deferred initialization:
mutation is about changing the value of an existing variable,
deferred initialization is about declaring a variable at one point, and initializing it later.
The Rust compiler tracks whether a variable has a value at compile-time, so unlike C there is no risk of accidentally using an uninitialized variable (or unlike C++, a variable that was moved from).
The most important reason for using deferred initialization is scope.
fn main() {
let x;
let mut v = vec!();
{
x = 2;
v.push(&x);
}
println!("{:?}", v);
}
In Rust, the borrow-checker will validate that a reference cannot outlive the value it refers to, preventing dangling references.
This means that v.push(&x) requires that x lives longer than v, and therefore be declared before v.
The need for it does not crop up often, but when it does other solutions would require run-time checks.

What's the difference between placing "mut" before a variable name and after the ":"?

Here are two function signatures I saw in the Rust documentation:
fn modify_foo(mut foo: Box<i32>) { *foo += 1; *foo }
fn modify_foo(foo: &mut i32) { *foo += 1; *foo }
Why the different placement of mut?
It seems that the first function could also be declared as
fn modify_foo(foo: mut Box<i32>) { /* ... */ }
If you're coming from C/C++, it might also be helpful to think of it basically like this:
// Rust C/C++
a: &T == const T* const a; // can't mutate either
mut a: &T == const T* a; // can't mutate what is pointed to
a: &mut T == T* const a; // can't mutate pointer
mut a: &mut T == T* a; // can mutate both
You'll notice that these are inverses of each other. C/C++ take a "blacklist" approach, where if you want something to be immutable you have to say so explicitly, while Rust takes a "whitelist" approach, where if you want something to be mutable you have to say so explicitly.
mut foo: T means you have a variable called foo that is a T. You are allowed to change what the variable refers to:
let mut val1 = 2;
val1 = 3; // OK
let val2 = 2;
val2 = 3; // error: re-assignment of immutable variable
This also lets you modify fields of a struct that you own:
struct Monster { health: u8 }
let mut orc = Monster { health: 93 };
orc.health -= 54;
let goblin = Monster { health: 28 };
goblin.health += 10; // error: cannot assign to immutable field
foo: &mut T means you have a variable that refers to (&) a value and you are allowed to change (mut) the referred value (including fields, if it is a struct):
let val1 = &mut 2;
*val1 = 3; // OK
let val2 = &2;
*val2 = 3; // error: cannot assign to immutable borrowed content
Note that &mut only makes sense with a reference - foo: mut T is not valid syntax. You can also combine the two qualifiers (let mut a: &mut T), when it makes sense.
The following natural language translation seems to clear things up for me...
let x = value;
x {binds immutably} to {immutable value}
let mut x = value;
x {binds mutably} to {possibly mutable value}
let x = &value;
x {binds immutably} to {a reference to} {immutable value}
let x = &mut value;
x {binds immutably} to {a reference to} {mutable value}
let mut x = &value;
x {binds mutably} to {a reference to} {immutable value}
let mut x = &mut value;
x {binds mutably} to {a reference to} {mutable value}
where
{binds mutably} means the binding can be reassigned
{mutable value} means the value's contents can change
To be able to mutate a value you need both a mutable binding and a mutable value
Note:
Reference mutability vs target mutability
A reference variable such as x, as in let x = &mut y, is a separate variable from the target variable y it is pointing to. In particular, x has its own location on the stack and mutability permissions. As such, if x is immutable, as it is here, then it cannot be reassigned to point to some other variable. That restriction is separate from the ability to mutate the target through it, as in *x = some_value; the target is a distinct variable with its own mutability permissions. However, if w is mutable, as in let mut w = &mut p, then it can indeed be reassigned to point to some other similarly typed variable: w = &mut z.
Mutable Variable of Reference Type
When you have
let mut x: &T = value;
This means that x is variable that refers to an instance of T, as if by storing the memory address of the T instance in x's value. This reference (i.e. the "memory address") is the subject of mutability in this context: x can be modified to refer to a different instance of T like this:
x = some_other_T_instance;
but the referant (i.e. the value of the T instance to which x refers) cannot be changed via x:
// Illegal
*x = a_different_value;
Immutable variable of Mutable Reference type
When you have
let x: &mut T = value;
This means that x is a variable that refers to a mutable instance of T. In this case, the referent (i.e. the actual value) is the subject of mutability. It can be modified through the reference like this
*x = some_other_value;
but the reference itself (i.e. the "memory address" in the variable x) cannot:
// illegal
x = a_different_value;

How to initialize a variable twice?

I'm trying to initialize a variable twice in 2 different functions without the second initialization having effect on the first.
float X;
void setup()
{
size(400, 400);
background(255);
}
void draw()
{
Rect1();
Rect2();
}
void Rect1()
{
fill(255,0, 0);
rect(X, 20, 40, 40);
X=20;
}
void Rect2()
{
fill(0, 255, 0);
rect(X, 200, 40, 40);
X=50;
}
You code seems to be "demonstration" code, but it doesn't really do anything significant other than show that you probably need to first sit down and learn a bit about Processing before you continue - hit up processing.org and run through some of the tutorials. It's worth it.
The code you gave can be written much more sensibly, but instead I'll answer the question; Processing uses a variation on Java's scoping rules: a local variable trumps an object instance variable, which trumps a global variable:
int x = 0;
int y = 50;
class Thing {
int y = 10;
Thing() {
// x is global, y is global and object instance
println("x (in Thing): "+x);
println("y (in Thing): "+y);
declareAndCheck();
}
void declareAndCheck() {
// now we make some local variables: they win.
int x = 40;
int y = 100;
println("x (local declared): "+x);
println("y (local declared): "+y);
}
}
void setup() {
println("x (global): "+x);
println("y (global): "+y);
Thing t = new Thing();
// and global is still global
println("x (global, again): "+x);
println("y (global, again): "+y);
}
This will generate the following output:
x (global): 0
y (global): 50
x (in Thing): 0
y (in Thing): 10
x (local declared): 40
y (local declared): 100
x (global, again): 0
y (global, again): 50
Why? First we see this:
x (global): 0
y (global): 50
because x and y are global variables with values 0 and 50. Simple enough. then we see:
x (in Thing): 0
y (in Thing): 10
because in the "Thing" object, we have an object instance variable 'y', which wins the naming conflict between it, and the global variable.
Then we enter declareAndCheck, where we see:
x (local declared): 40
y (local declared): 100
because we now have a global x, and a local x, and local always wins, and we have an instance y, and a local y, and again local always wins.
Finally we print x and y in global context again, and because there is no conflict, we see:
x (global, again): 0
y (global, again): 50
And if that did not make sense to you, run through those tutorials, they teach you programming in Processing =)