Can a field be upgraded from const to var?

Suppose we have:

let v = {
  c: Int;
};

Can the canister with this be upgraded to

let v = {
  var c: Int;
};

without losing c state?

This only becomes an issue once you have stable variables. If we have

stable let foo = {
  count = 0
};

then when upgrading we’ll get a warning of

Incompatible stable signature will cause data loss:
stable variable foo of previous type
  {count : Nat}
cannot be consumed at new type
  {var count : Nat}

and data will be lost.

So, how can we fix this? We can migrate our data to a new structure, either in a post_upgrade hook, using a helper function, or by using an upgrade method. Since going from count to var count is simple, let’s do a helper function.

stable let foo = {
    count = 0;
  };

  private func migrate_foo () : {var count: Nat} {
    return {
      var count = foo.count;
    }
  };

  stable let foo_v2 = migrate_foo();

We can keep the original foo, and then set foo_v2 equal to the result of our migrate_foo function during initialization. This will transform the previous type into our new type, and set a new variable.

After the data and our public methods are upgraded to use foo_v2, we can safely delete our stable foo variable in a future upgrade.

Here’s some example code: Motoko Playground