0

I have a struct that has many properties. This struct has a function that makes a decision, and passes the appropriate property to a different function that performs arithmetic on the referenced property. Why am I not able to do this kind of multi-leveled reference passing in rust?

https://play.rust-lang.org/?gist=ef0cfc561afc2e4374475b93b2f62ab0&version=stable

struct Foo {
    pub a: u8
}

impl Foo {
    pub fn new() -> Foo {
        Foo {
            a: 1
        }
    }

    pub fn calculate(&mut self) {
        self.a += 1; // This is perfectly fine
        self.add_later(&mut self.a); // This throws an error
    }

    fn add_later(&mut self, arg: &mut u8) {
        *arg += 1;
    }
}

fn main() {
    let mut bar = Foo::new();
    println!("{}", bar.a);
    bar.calculate();
    println!("{}", bar.a);
}
user2936448
  • 335
  • 4
  • 16
  • if `add_later` doesn't actually use `&mut self`, why pass that to the function at all? You can make it a normal function instead. Otherwise this is like https://stackoverflow.com/questions/27335252/how-can-i-call-a-mutating-method-while-holding-a-reference-to-self and I think others. – loganfsmyth Oct 26 '17 at 04:22
  • @loganfsmyth Isn't it considered good practice to keep the behavior relating to Foo inside the Foo implementation? That's the only reason I have the function defined in there. – user2936448 Oct 26 '17 at 04:32
  • If something is conceptually a method then sure, but your function never even uses `self`, so it definitely isn't method-like. – loganfsmyth Oct 26 '17 at 04:40
  • 1
    @user2936448, you can create a "method" without `self`. You have one already: `new()` – red75prime Oct 26 '17 at 04:44
  • @loganfsmyth I get what you're saying, but in my actual implementation I need to use 'self' in the add_later function because it updates additional properties of the struct along with changing the 2nd parameter. I didn't do anything with self in this example because I didn't need to use self in order to demonstrate the compiler error. – user2936448 Oct 26 '17 at 04:49
  • Sounds good, that'd what I was trying to clarify. This seems like a duplicate of the question I linked above then. – loganfsmyth Oct 26 '17 at 04:52
  • It would be great if your example more closely represented your use case. Given your description above, I'm not sure why [this isn't acceptable](https://play.rust-lang.org/?gist=a5de15f8a75bb27d8cbfadc996a82b64&version=stable). That is, if you're just modifying fields of the struct _and the struct is very much aware of these fields as it owns them already_, why not just call the method with no arguments? – Simon Whitehead Oct 26 '17 at 05:15
  • @SimonWhitehead I am making an emulator where the CPU (Foo) holds a list of u8 registers (a, b, c,.. etc). I want to make a generic add(&reg1, &reg2) function to add 2 registers. This means that I can have 1 function that will handle all variations of ADD(R, R). After the addition of two registers, one specific F register _also_ gets its bits updated based on the calculation between the two parameters. – user2936448 Oct 26 '17 at 06:10
  • @SimonWhitehead Well that's a coincidence. I looked at your github and realized you are working on a GB emu in rust. This is the same project I am working on, except I'm re-doing mine in Rust. I looked at how you handled this problem out of curiosity, and you wrote a unique function for every single case and have 4,000 lines of CPU code. This is something that I want to avoid which is why I posted this question. – user2936448 Oct 26 '17 at 06:20
  • In that case, can't you just store the registers in an array and pass the index of the modified register as the parameter? Bonus, it will probably be easier to implement since such an index is already stored in the emulated code. – Jmb Oct 26 '17 at 06:42
  • @user2936448 hah - yes, I did do that didn't I. My emu is still heavily in active development. I do plan on cleaning that up but it was helpful for me to write tracing code while I was implementing it. I will clean it up at some point though :D To answer your question: most of the opcodes you'll be implementing have defined destinations for the results of the operations. So for the most part, [you can structure your code somewhat like this](https://play.rust-lang.org/?gist=d223a0cbdc55630324e857e6b8220fc7&version=stable) to do what you want if that appeals to you. – Simon Whitehead Oct 26 '17 at 09:37
  • @user2936448 There are _much_ fancier options out there if you're looking for as much code-reuse as possible. One that comes to mind [specifically is Mooneye-GB](https://github.com/Gekkio/mooneye-gb/blob/master/src/cpu/ops.rs) - you might find the source to that interesting. – Simon Whitehead Oct 26 '17 at 09:38
  • 2
    You are trying to write **wrong** code here. The correct would be to pass `&mut self` and use `a` field of `self`. There is a very simple error caused by the borrow checker - you can't have more than one mutable reference to a object at a time. I don't even know what to discuss here. – VP. Oct 26 '17 at 10:23
  • 1
    Possible duplicate of [How can I call a mutating method while holding a reference to self?](https://stackoverflow.com/questions/27335252/how-can-i-call-a-mutating-method-while-holding-a-reference-to-self) – trent Oct 26 '17 at 14:50
  • This is a duplicate of a question I already answered to, but I cannot find it. – Boiethios Oct 27 '17 at 13:01
  • 1
    You might want to look at [this answer](https://stackoverflow.com/a/46144233/1600898), which covers a similar case. – user4815162342 Oct 28 '17 at 16:09

0 Answers0