cairo icon indicating copy to clipboard operation
cairo copied to clipboard

bug: cannot assign mut tuple

Open milancermak opened this issue 1 year ago • 4 comments

Bug Report

Cairo version:

eaf16c6eb

Current behavior:

Trying to assign the result of a function call to a tuple of mut variables results in a compilation error.

fn mul2(v1: u64, v2: u64) -> (u64, u64) {
    (v1 * 2, v2 * 2)
}

fn main() {
    let mut v1 = 10;
    let mut v2 = 20;
    (v1, v2) = mul2(v1, v2);
}

Compiling this throws

error: Invalid left-hand side of assignment.
 --> no_tuple.cairo:8:5
    (v1, v2) = mul2(v1, v2);
    ^******^

Error: Compilation failed.

Expected behavior:

It should be possible to assign to a tuple of mutable variables. In the example above, the new values for v1 and v2 should be 20 and 40.

The assignment works with let (v1, v2) = mul2(v1, v2); but that's not the intended behaviour and can lead to subtle bugs. Assigning to a single mutable variable also works (if mul2 would return only a single value, v1 = mul2(v1); is fine), so this would just be an extension of the functionality onto tuples.

milancermak avatar Jun 30 '23 09:06 milancermak

You can do let (u1, u2) = mul(v1, v2); u1=v1; u2=v2;. I'm not sure I'm in favor of your proposed syntax. For one, it's not supported in rust:) If we would support something liek this, it wouldn't be just for tuples though, but for general pattern. Probably more like let (assign v1, assign v2) = mul(v1, v2) or something equivalent.

spapinistarkware avatar Jul 26 '23 07:07 spapinistarkware

Why is it different with tuples then? If I have only a single mut variable, all is fine:

fn mul2(v1: u64) -> u64 {
    v1 * 2
}

fn main() {
    let mut v1 = 10;
    v1 = mul2(v1);
}

milancermak avatar Jul 26 '23 07:07 milancermak

It's not different with tuples. you can still do

let mut x = (1,2);
x = foo();

tuple type is the same as other stuff. The request here was to introduce some kind of tuple unpacking into existing variables.

spapinistarkware avatar Jul 26 '23 12:07 spapinistarkware

Concrete suggestion: Add another pattern kind, Assignment expr. Suggested syntax: -> x It can be used wherever a pattern can be used (let and match arms, and nested in other patterns). Examples:

let (_, (->b.x.y, c)) = (0, (1, 2));
let Struct { x: ->a, y: b, .. } = bar();

match foo() {
  Some(->x) => {},
  None => {},
}

// Question: should we have a short syntax for y: ->y ?
let Struct { x, y: ->y } = Struct { x: 5, y: 6 };
// For example
let Struct { x, ->y } = Struct { x: 5, y: 6 };

spapinistarkware avatar Jul 27 '23 11:07 spapinistarkware