Wrapping a stable var

We really need a way to skip the postupgrade/preupgrade checks as they’re taking up like 600 of our Wasm functions (out of the 6000 allowed), and creating a lot of code complexity. Also, life would be so much easier if things just persisted.

This appears to work but I’m not sure it will in practice. I’m using @icme’s StableRBTree library.

When using a non-OO library you have to replace the stable variable with each state change, and that’s not good when you have a complex OO system. I thought this may get around the problem.

  type dbType = RBT.Tree<Nat, Nat>;

  stable var characterDB : dbType = RBT.init<Nat, Nat>();

  type dbWrapper = {
    var db : dbType;
  };

  public shared({ caller }) func test() : async [(Nat, Nat)] {
    let w = {var db = characterDB};
    modifyDB(w);

    Iter.toArray(RBT.entries(w.db));
  };

  func modifyDB(w : dbWrapper) {
    w.db := RBT.put(w.db, Motoko.compareNat, 1, 33);
  };

Looks like it is just a pointer update, not a full copy of the entire tree.

This may explain it a bit better

  type dbType = RBT.Tree<Nat, Nat>;

  stable var characterDB : dbType = RBT.init<Nat, Nat>();
  type dbWrapper = {
    var db : dbType;
  };

  public shared({ caller }) func test() : async [(Nat, Nat)] {
    var db = characterDB;
    let w = {var db = db};
    modifyWrapper(w);
    modifyDB(db);

    Iter.toArray(RBT.entries(w.db));
  };

  func modifyDB(db : dbType) {
    db := RBT.put(db, Motoko.compareNat, 1, 33);
  };

  func modifyWrapper(w : dbWrapper) {
    w.db := RBT.put(w.db, Motoko.compareNat, 1, 33);
  };

type error [M0073], expected mutable assignment target

yeah ill write a wrapper library that makes it easier to use in our system and that may give a few ideas. map/mapFilter for example.

Without line numbers of where the error is I’d say it’s happening here. Your input parameter is called db, and it’s not of type var so it can’t be mutated.

If you can point me to where the error is I can help you further

Yeah sorry I know why the error was occurring, I was just showing that wrapping the mutable variable allows us to pass it through functions and classes. That was the bit I was missing before.

1 Like

Yep, as long as you wrap it in a stable type like a record you should be fine.

Just curious though, why do you need to wrap the db?

because we’ve got a OO ORM with transactions, indexes and all sorts of stuff and I couldn’t imagine how to build that without passing the dbs as arguments