Private mutable arrays + questions

I have a few questions/misunderstandings regarding Arrays and mutability as well as privacy:

  1. Shareable state: The documentation says that “immutable arrays are safe to send and share, while mutable arrays can not be shared or otherwise sent in messages”. As far as I understand this, I can return the content of a mutable array declared using var in a query call but I shouldn’t be able to return it in a shared function. However, the following code works. Actually, this sentence says that we cannot even return a var in a query call since a query call sends a “message”, doesn’t it? I wonder why the following works:
var a : [Text] = ["one", "two", "three"]; // a mutable array that should not be shareable?
public shared func shareMutable() : async [Text] {
  return a;
};
  1. There is an example of a mutable array where an array is defined with let but contains type [var Nat]. I don’t understand the use of it when I could just as well define the array using var. In what case would the first version be useful in contrast to the second version:
let a : [var Nat] = [var 1, 2, 3] ;
var b : [Nat] = [1, 2, 3];
  1. Specifically, what I’m trying to find out is, if it is possible to have an array that is mutable and private in the sense that the owner of the canister can change its state by calling a shared function with an assert statement, but which is impossible(!) to send through a query call. My guess is that I don’t understand private state yet because my assumption would be that this shouldn’t be possible since the array a is declared as private (I have seen this kind of declaration somewhere but can’t find it in the docs):
  private var aPrivate : [Text] = ["one", "two", "three"];

  public query func readAPrivate() : async [Text] {
    return aPrivate;
  };

What am I getting wrong?

A mutable array is one with type [var T]. In contrast, in your examples, you have mutable variables holding immutable arrays. That’s an additional level of indirection.

In the latter case you cannot mutate the array itself. This makes a difference in terms of performance as well as expressiveness. For example:

let a = [var 0, 1, 2, 3];
let b = a;
b[0] := 5;
assert (a[0] == 5);

var c = [0, 1, 2, 3];
var d = c;
d := [5, 1, 2, 3];
assert (c[0] == 0);
1 Like

Thank you very much for your answer! Picking up on my case 3 I would go for a solution like this one (maybe this is useful for somebody else as well):

  var myArray = [var 0, 1, 2, 3]; // mutable variable (non-shareable) that holds a mutable array

  // public query func shareMyArray() : async [var Nat] {
  //   return myArray; // This doesn't work since it contains a non-shared return type [var Nat]
  // };

  public query func sharePartOfMyArray() : async Nat {
    return myArray[0]; // I can get a single value from a mutable array
  };

  public shared(msg) func changeMyArray() : async Nat {
    assert(msg.caller == owner);
    let newArray = [var 5, 6, 7, 8];
    myArray := newArray; // However, the whole array can be changed and I can then return single values from it
    return myArray[0];
  };

However, I’m still not sure about the use of private in the context of variables, i.e.:

private let myThirdArray = [0, 1, 2, 3];
  public query func shareMyThirdArray() : async [Nat] {
    return myThirdArray;
  };

What does private mean in this context and why is it possible to “reveal” a private variable through a query call? This compiles successfully and I wonder what the use of a privately declared variable could be. Or phrased differently: To whom is this variable private when it can be “revealed” through a query call that anyone can call?

I’m not quite sure I understand the question. Private just means that clients cannot see the variable (in an actor, all variables are in fact private).

The query is not “revealing” the private variable. It is merely returning some (array) value. That this value happens to be read directly from a variable is an immaterial implementation detail of the method and not observable by clients.

PS: As for your declaration of myArray: it’s rarely useful to have two layers of mutability. You typically either want an immutable variable holding a mutable array, or a mutable variable holding an immutable array. The way your example uses it, the latter would be sufficient.

I think this answers my question and the confusion stems from how I as a non-programmer understand private: My expectation for a private variable is that it cannot return the value assigned to it (to the outside world/outside of the actor) and can only be used to do stuff internally within the actor.

That makes sense, thank you!