A list of puns related to "Mutability"
The following code works perfectly:
#[derive(Debug)]
struct A {
f1: u32,
f2: u32,
f3: u32
}
#[derive(Debug)]
struct B<'a> {
f1: u32,
a: &'a mut A,
}
fn main() {
let mut a: A = A{ f1: 0, f2: 1, f3: 2 };
// b is immutable
let b: B = B{ f1: 3, a: &mut a };
// but can change a field in b.a !!
b.a.f1 += 1;
println!("b is {:?} ", &b);
}
b
is defined as immutable struct B
but has a mutable reference to a struct A
. Rust will allow changing a field inside the A
referenced by b.a
using this line b.a.f1 += 1;
. The code will print:
"b is B { f1: 3, a: A { f1: 1, f2: 1, f3: 2 } }"
I convinced myself this is allowed because we are not changing b
here. We are changing an A
referenced by b
, right?
But! if i slightly change the code, by placing the b.a.f1 += 1;
line in an impl block like so, the code does not compile:
#[derive(Debug)]
struct A {
f1: u32,
f2: u32,
f3: u32
}
#[derive(Debug)]
struct B<'a> {
f1: u32,
a: &'a mut A,
}
impl B<'_> {
// this will not work
pub fn changeme(&self) {
self.a.f1 += 1;
}
}
fn main() {
let mut a: A = A{ f1: 0, f2: 1, f3: 2 };
// b is immutable
let b: B = B{ f1: 3, a: &mut a };
b.changeme();
println!("b is {:?} ", &b);
}
Compiling playground v0.0.1 (/playground)
error[E0594]: cannot assign to `self.a.f1`, which is behind a `&` reference
--> src/main.rs:17:9
|
16 | pub fn changeme(&self) {
| ----- help: consider changing this to be a mutable reference: `&mut self`
17 | self.a.f1 += 1;
| ^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers
My theory collapsed. Why does rust allow the first version but not the second? I understand that placing a &mut self
will make the code compile. My question is why is mut
not needed in the original code?
Everyone talks about advantages of functional languages over object oriented.. I'm curious to hear everyone's thoughts on the advantages of Object oriented instead. Particularly been thinking about mutability.
Benefits of Immutablity
- Hard to accidentally change a variable you didn't intend to change.
- Less likely to accidentally refer to the wrong variable
This study suggests using a functional language does indeed reduce bugs significantly:
https://web.cs.ucdavis.edu/~filkov/papers/lang_github.pdf
Benefits of Mutability
- Performance and memory wise mutability gives some advantages, though proper compiler level optimization helps a lot on this front.
- Managing state seems much harder with functional code.. such as having a car object in a game and you have to throw away the old car every frame when you update it's speed, I think your main loop would have to be recursive with tail optimization to keep track of game state? Doesn't feel as clean. Not a functional coding pro.
- Seem all around easier.. and a little bit like functional languages are the Esperanto of programming languages but that might just be my bias from having more experience with OO.
- Can use iteration instead of recursion, which is often easier to reason about
- At the end of the day you need to interact with mutable information anyway in functional programming.. files, database, networks, etc. So 'purely' functional isn't completely honest
One of the data points I found particularly interesting is in this study it was found that Object Oriented languages tend to be more productive than functional languages, found another study that indicating the same thing on this front though I can't find it at the moment:https://medium.com/smalltalk-talk/smalltalk-s-proven-productivity-fe7cbd99c061
I do believe at a minimum modern languages should support immutability by default but wondering if there is a better way or specific cases when mutability is needed.
One basic question I find hard to grasp coming from other languages. When we declare variable as mut, does that mean that we can reassign values to that variable, does that mean we can change a value that variable holds if for example value is stored on the heap or both? Can we somehow make that you can reassign value to variable but not change it? Or vice versa? Thanks
I've been thinking a lot about Mutability vs Immutability for our programming language, Flogram, as well as whether there is a way to 'bend the curve' and find an alternative that gets the pros of each approach.
At a minimum, I'd like to go with Rust's approach of mutability by default. But it would be nice to find an alternative as long as it didn't overly complicate things.
PROs of allowing mutability:
- Memory doesn't need to be reallocated or copied, better performance is achievable
- Simple to think about and all programmers have worked with such a language
- Allows Objects, which boosts productivity
PROs of forced immutability:
- Know that some other function didn't change a variable that you forgot about decreasing
- Better self-documentation of code
So I started thinking about an alternative approach: Variables may be mutated but if so, they must be renamed (or explicitly not renamed) before they are reused.
Syntax is definitely not finalized.
For example:
# mut declares a variable to be mutable
mut name:string = "Donald"
name = name + "Biden"
full_name <- name #rename name to full_name
#From this point onward, the same memory location that was being referred to as 'name' must be referred to as 'full_name'
If instead you wish to re-use the same name you can do something like this:
mut speed:int32 = 10
speed += 1
>speed< # Don't change the name
I believe this approach shares all three of the above PROs:
- If you try to use the variable "name" after it's been removed, a compiler error will prevent it and the bug you were about to create
- Changing the names of variables when the value they hold changes helps self document
- Great performance, if it's an array or an object, don't need to create a new array or object and copy old one, just add value
But does come with CONs:
- Can't change the name of object variables, so those have to be treated differently or overwritten but you can change the name of the current instance of the mutated object within the current function every step to reflect those changes
- More complicated and just one more thing to think about, I want to avoid of complexity that comes with having to worry about ownership all over the place in Rust for example.
I want to find the best trade-off between performance, productivity, and security. Definitely open to other ideas or tweaks to this.
I want to hear your thoughts on mutability and immutability
... keep reading on reddit β‘So I am pretty confident that reference counting would be 100% enough as a GC for a non-lazy language without mutable values. Am I missing something? Is there some way to have something (indirectly) hold a reference to itself?
I'm a C developer who's been checking out Rust because I really like a stronger type system, but I've come across an issue while writing some toy programs to practice the mutability rules. Essentially, I've got several instances of structs that I'd like to update with different data throughout the program. The C way of doing this would be to pass a pointer of the struct to void functions and have those functions write back to the structs through the reference, but obviously that causes the rust compiler to error on "multiple mutable references". My next thought was to write a bunch of trait functions for my structs that would update the proper data, kind of like how you might have several public methods in an object class in Java, but it appears that this really just kicks the can down the road since wherever you end up calling all the trait functions also would need to use mutable references.
So before I continue throwing stuff at the wall, I wondered if someone more knowledgeable could enlighten me on the recommended design pattern for updating a struct's contents several times throughout a program in Rust. I'm aware of Rust's unsafe blocks, but I'm hoping that isn't necessary to what I'd like. Much thanks.
Hi people,
I'm currently trying to build a page cache for a small database project. I decided to go with interior mutability since basically my whole project depends on it, and propagating `mut` gets a bit ugly. My struct looks like this:
pub struct Pager {
page_cache: RefCell<HashMap<PageIdentifier, Page>>,
}
and I'm trying to read a page and return it's reference for deserialisation later on:
pub fn read_page(&self, page_identifier: &PageIdentifier) -> Result<&Page, PagerError> {
self.page_cache.borrow().get(page_identifier).ok_or(PagerError::FailedToReadPage)}
This unfortunately does not compile due to the local borrow `self.page_cache.borrow()`. Is there any other way to return this reference and also potentially handle errors? One solution I found relied on existential types:
pub fn read_page<*'a*>(&self, page_identifier: &PageIdentifier)
-> impl Deref<Target=Result<&Page, PagerError>> + 'a {
self.page_cache.borrow().get(page_identifier).ok_or(PagerError::FailedToReadPage)}
But this fails with `the trait `Deref is not implemented for Result<&[u8; 8192], PagerError>` which I can't implement myself due to trait implementation limitations.
How can I do shared mutability in rust? I mean one that does not depend on scope.
I understand that depending on conditions certain invariants must be kept to keep the "time-shared" access exclusive.
My main question is how can this be structured? Say you have a Bus
that contains a fn transfer(&mut self, ...)
function. Then you have multiple Device
entities that need access to this bus to call the transfer function (one at a time, interlieved as needed). How can this be achieved wrt. data structures?
Best I can come up with is to store a &Bus
in the Device
and then somehow have something like Bus::reconfigure(&self) -> Mutex<Self>
which "borrows" the bus mutably for a duration. But I don't understand how to construct this.
I've been trying to use Rust for working on a graph structure (in a compiler) and the suggested solution is to use an Arena/(Vec + indices).
Vec with indices seem to be everyone's favorite so I used it as well but I ran into a problem: How do you mutate 2 elements in the arena at the same time?
Lets say I have a hypothetical structure like this:
struct FnDef {
stmts: Vec<ArenaId>,
}
enum Stmt {
VarDef(ArenaId),
}
struct Var {
ty: Type // need to mutate this
}
The ids are indices. I want to mutably traverse through the graph like this:
let fn_def_id = get from somewhere;
let fn_def = arena.get_mut(fn_def_id); // arena is mutably borrowed
for stmt_id in &fn_def.stmts {
let stmt = arena.get_mut(stmt_id); // error: arena is already mutably borrowed
match stmt {
var => var.ty = do type check and assign
}
}
The reason I need to traverse mutably is because I need to do typechecking so need to modify type field of various nodes.
So the problem is get_mut is borrowing the whole arena. But borrowing 2 nodes is not a safety issue as long as they are different nodes.
So one solution can be to use RefCell and arena.get instead. So I'll get an immutable reference to RefCell which I can then borrow_mut from.
So change the code to:
let fn_def = arena.get(fn_def_id); // arena is immutably borrowed
for stmt_id in &fn_def.borrow().stmts {
let stmt = arena.get(stmt_id); // fine, arena is immutably borrowed x2
match stmt.borrow_mut() {
var => var.ty = do type check and assign
}
}
This is fine, but is it the best way? Can I restructure my code to get around having to use RefCell? What if I need to allocate as well? Then I'll certainly need to have mutable access to arena (or use arena with stable addresses like typed_arena instead so alloc can also be done using an immutable reference).
How do people deal with these issues? Maybe there's a pattern or something that I'm missing.
Edit: Thanks everyone for the suggestions. Really helpful!
I'm porting my python program to Rust and one thing I keep running into is this programming scenario:
In python, I have list_A that is a list of button components.
I have list_B that stores the id's of selected buttons from list_A.
When I need to do something on a component listed in list_B. I cycle through list_A to get the matching button. Then do something on the button.
=====
I was hoping to do the something similar in Rust, but make list_B hold references instead of id's. This would skiip the searching part.
But now I think that's not possible since keeping references around means I can't mutate them.
Is there a workaround to this ?
Hey everyone! I'm working on a Gameboy emulator and have been making good progress, but I've come to realize the current way my execution cycle works is pretty limited performance wise. What I'm doing right now is using fetch() to get the next instruction from the game's ROM by returning an enum which contains all the information needed to modify the state of the emulator appropriately. The problem is that, in order to get around Rust's borrow checker, I've got a method in my emulator which takes a RegisterId and returns the correct instance variable as a mutable reference so that I can modify it. So, my fetch() method is not returning an enum with the registers themselves, but only the ID's. This means each time I fetch a new instruction I need to perform a lookup to determine which register will be affected. What I'd like to do instead is returning a mutable reference to the emulator's registers within my enum, and then modifying that directly in my execute()'s match pattern.
Here's a condensed version of what I'd like to achieve:
pub struct ByteRegister(pub u8, pub RegisterId);
enum TestCommand {
ChR8(ByteRegister)
}
pub struct TestGameboy {
a: ByteRegister,
pc: ProgramCounter
}
fn fetch(mut gb: &mut TestGameboy) -> TestCommand {
let op = gb.pc.0;
match op {
_ => ChR8(gb.a) // Pretty sure I need &mut here, but won't work unless I introduce lifetime annotation to TestCommand
}
}
pub fn execute(mut gb: &mut TestGameboy) {
let mut command = fetch(gb);
match command {
ChR8(ref mut reg) => reg.0 = 8
}
println!("{}", gb.a.0) // Should print 8, prints 0
}
pub fn main() {
let mut gameboy = TestGameboy { a: ByteRegister(0, RegisterId::A), pc: ProgramCounter(0) };
loop {
execute(&mut gameboy);
}
}
Mutating something in Rust that was not declared as &mut
is UB. This means that I cannot cast a reference to a mutable reference and mutate it. This makes sense because of aliasing etc. The same rule exists for the raw pointers as well. So casting a *const
to *mut
and mutate it is also UB. So, the only way to do interior mutability (from a reference to a mutable reference) is with UnsafeCell
.
So, I was wondering what happens if I get a pointer from C? In C these rules "don't exist". At least it is not UB to mutate data from a pointer even if it is not exclusive. Let's ignore the possible issues like data races etc. Let's assume it is a single-threaded application. Is it in that case fine to cast a *const
to *mut
at any time?
I was watching this video: https://www.youtube.com/watch?v=u80WqduxdhA and I had a peak in the implementation and this code looked fishy to me
use core::marker::PhantomData;
extern "C" {
fn mutex_lock_c();
fn mutex_unlock_c();
}
pub struct Mutex<T> {
inner: T,
}
impl<T> Mutex<T> {
pub fn init(t: T) -> Self {
Mutex { inner: t }
}
pub fn acquire(&self) -> MutexGuard<'_, T> {
unsafe { mutex_lock_c() };
MutexGuard {
inner: &self.inner as *const _ as *mut _,
data: PhantomData,
}
}
}
pub struct MutexGuard<'a, T> {
inner: *mut T,
data: PhantomData<&'a T>,
}
impl<'a, T> MutexGuard<'a, T> {
pub fn get_mut(&mut self) -> Option<&mut T> {
unsafe { self.inner.as_mut() }
}
}
impl<'a, T> Drop for MutexGuard<'a, T> {
fn drop(&mut self) {
unsafe { mutex_unlock_c() };
}
}
Isn't this UB? Even if the code ensures that there is only one mutable reference at any time. It should still be UB. So, does the interior mutability rule exist in Rust when working with pointers from the C world?
Hey does anyone have that illustration of the replication crisis/the mutability of data where data is a model surrounded by many artists that are drawing it in different art styles? That would very helpful.
I recently read about the Index
trait and what some people view as deficiencies with it. Index<T>
defines a type Output
and a function with this signature: fn index(&Self, T) -> &Output
. To help myself understand how this trait might be used, I'm trying to figure out if there's a way to define a struct foo
such that foo[n] == n
holds for all n: usize
. I suspect there's some way to do this by temporarily storing the argument in the struct and returning a reference to it, but I don't understand the shared mutability types well enough to figure out how. Or maybe it's not possible without allocating? I also don't understand how Copy
interacts with auto-dereferencing well enough to see if this is a fool's errand or not.
I really would really appreciate anyone willing to take a few minutes and explain to me how this works. Thanks in advance!
I am creating a small model for a D&D type program, and I encounter the following issue:
pub mod abilities;
pub mod races;
pub mod characters;
use crate::abilities::Ability;
use crate::abilities::AbilityScore;
use crate::races::HUMAN;
use crate::characters::Character;
fn main() {
println!("Hello, world!");
let strength = Ability {
name: String::from("Strength"),
short: String::from("STR"),
};
let charisma = Ability {
name: String::from("Charisma"),
short: String::from("CHA"),
};
let wisdom = Ability {
name: String::from("Wisdom"),
short: String::from("WIS"),
};
let dexterity = Ability {
name: String::from("Dexterity"),
short: String::from("DEX"),
};
let constitution = Ability {
name: String::from("Constitution"),
short: String::from("CON"),
};
let intelligence = Ability {
name: String::from("Intelligence"),
short: String::from("INT"),
};
let ch = Character {
name: String::from("Yodo the great"),
hp_max: 8,
hp: 8,
race: HUMAN,
base_ability_scores: vec[
AbilityScore { ability: strength, score: 8 },
AbilityScore { ability: charisma, score: 12 },
AbilityScore { ability: wisdom, score: 12 },
AbilityScore { ability: dexterity, score: 15 },
AbilityScore { ability: constitution, score: 12 },
AbilityScore { ability: intelligence, score: 12 },
]
};
ch.apply_race();
for ab in &ch.base_ability_scores {
println!("Ability modifier for {} is {:+}", ab.ability.name, ab.modifier())
}
}
The call to ch.apply_race() should apply the traits for a human, which would increase all the ability scores with one.
use crate::races::Race;
use crate::abilities::AbilityScore;
#[derive(std::fmt::Debug)]
#[derive(std::clone::Clone)]
pub struct Character<'a> {
pub name: String,
pub hp_max: i32,
pub hp: i32,
pub race: Race<'a>,
pub base_ability_scores: Vec<AbilityScore>
}
impl Character
... keep reading on reddit β‘Please note that this site uses cookies to personalise content and adverts, to provide social media features, and to analyse web traffic. Click here for more information.