Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

be clearer on mutability #134

Open
mimoo opened this issue Jun 20, 2024 · 11 comments
Open

be clearer on mutability #134

mimoo opened this issue Jun 20, 2024 · 11 comments

Comments

@mimoo
Copy link
Contributor

mimoo commented Jun 20, 2024

we're not super clear on what can be mutated and what cannot be.

For example, can this function call mutate thing?

let mut thing = 5;
stuff(thing);

imo we should make mutability when we're passing mutable values around. In rust we would have to write stuff(&mut thing). In noname everything is passed by value so I'm not sure what would be a good syntax (there is no such thing as stuff(&thing) for example. Maybe stuff(mut thing)?

How about this example:

fn stuff(arg: Field) { /* ... */ }

can the body of stuff mutate arg? I think it could only if we have fn stuff(mut arg: Field), which I don't think is something we currently have in functions/methods.

The best thing to do would be to create tests to showcase these examples

@katat
Copy link
Collaborator

katat commented Jun 20, 2024

fn stuff(mut arg: Field) makes sense to mutate an external variable inside the function.

atm, all the variables passing between the functions are done via copying their values. The reference variable is only usable at local scope.

@mimoo
Copy link
Contributor Author

mimoo commented Jun 20, 2024

arg, so now I'm wondering what this does exactly if stuff attempts to mutate a, does it fail to compile because stuff doesn't see a as mutable?

let mut a = 5;
stuff(a);

if this is the case then functions are pure, which might not be the worst thing for now...

@katat
Copy link
Collaborator

katat commented Jun 20, 2024

The function stuff(a) can be called with that mutable variable. Inside that function, that variable a is seen as immutable. As long as it doesn't directly mutate the argument a which is not mutable as the syntax mut is not supported for the function argument, it won't throw error.

@bufferhe4d
Copy link
Contributor

I faced this problem when I was planning to test the example given in #224 .

Below, even if the room variable is mut, we are not able to write functions like update_size since it is not possible to pass self as mut. I don't know if this is necessary to have but just found it relevant to share.

struct Room {
	pub beds: Field, // public
        size: Field // private
}

Room.update_size(self, size: Field) {
        self.size = size; 
        ^ error: self is not mutable
}

fn main() {
       let mut room = Room {beds: 2, size: 10};
       room.beds = 2; // allowed
       room.size = 5;  // not allowed
       room.update_size(5); // allowed
}

@mimoo
Copy link
Contributor Author

mimoo commented Nov 13, 2024

I think we're in a model where functions/methods have to produce a new object instead of updating the current object. It's more "functional" and doesn't really save you any constraints underneath so maybe we should keep it this way?

@katat
Copy link
Collaborator

katat commented Nov 13, 2024

mmm, I think it is a natural mind flow that people would like to modify the struct fields within the methods. Requiring them to return a new struct if modifications happen seems to be quite cumbersome (I may miss something here).

@mimoo
Copy link
Contributor Author

mimoo commented Nov 14, 2024

yeah I'm not against that path either, but the problem is... what keyword do we introduce for a mutable ref? &mut sounds ugly when we don't have references in the first place. Maybe Room.update(mut self, ...) would do?

but this might be weird for people coming from Rust, who will see mut self as a new copy of the previous self value that is mutable in that scope only.

Maybe mutref keyword then? But it's starting to get verbose :D

(this is where my train of thought stopped last time I thought about it, and then I figured the current way sort of works and doesn't add more lines of code)

@katat
Copy link
Collaborator

katat commented Nov 14, 2024

IIUC, the current mut keyword is seen as reference behind the scene already.

if var_info.mutable {

So maybe just mut [args] for simplicity and consistency with its existing let mut ... usage?

@mimoo
Copy link
Contributor Author

mimoo commented Nov 15, 2024

mmm, I would still vote for refmut/mutref because I personally would probably be confused by the mut alone. We might want to allow a mut as well just to say that the variable is mutable in that scope.

but also, when we are passing such a variable as argument to a function, I think we should have a syntax to indicate that the variable is going to be mutated. So in Rust we would have:

fn thing(val: &mut Field);
// ...
let mut x = 5;
thing(&mut x);

in noname what would be the equivalent of that code?

fn thing(val: mutref Field);
// ...
let mut x = 5;
thing(mutref x);

that looks ugly :D

@katat
Copy link
Collaborator

katat commented Nov 18, 2024

Cool. Let's go with the mutref for now. cc @bufferhe4d

@bufferhe4d
Copy link
Contributor

Cool. Let's go with the mutref for now. cc @bufferhe4d

Alright, I am on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants