Initializing a class

Hi I’m creating a wrapper for my graph (data storage) In the test actor, I initialize it let STR = Storage.Storage()- this will be in every drive The Storage() class contains the root_tree variable

var root_tree = T.Tree<Text, Text> ( _key, _val, _parent, _childs, _level, _hm_capacity, Text.equals, text.hash);

Question: Will the STR variable be constant when calling the canister? That is, its initialization? It is important for me to keep the original link to root_tree and not lose the information. In the tests, I checked that the data is stored in the local dfx sdk package, but its behavior in the working network is important to me

1 Like

Nope! You need to store your values in stable vars in the actor and pass those in as initialization variables when you reconstitute.

A good latter is to put a toStable() function that you call on preupgrade that returns the inputs Parameters for your class.

Hello Skilesare. It is not yet clear to me how to do this. For more understanding, I will present in more detail the scheme of classes and calls. Or I will provide the source code a little later. While I’m doing related things. Still, thank you, I’ll try to figure it out.

There’s an example mapping to/from stable types using the preupgrade and postupgrade hooks here, which hopefully should help: Stable variables and upgrade methods :: Internet Computer

1 Like

Written non a mobile…forgive the formatting

In class file

public type stableConfigType = {
   importantThing: Text;
};

public func defaultConfig() : stableConfigType      {
      return {importantThing =null;};
};



class myClass(config: stableConfigType){

    private let importantThing : Text = switch( stableConfigType.importantThing){
        case(null){//init code here};
        case(?val){ val};
    }

    public func toStable() : stableConfigType {
          {importantThing = ?importantThing;}
    }
    
}

In actor

 stable var classConfig : MyClass.stableConfigType = MyClass.defaultConfig();

 let myClass = MyClass.MyClass(classConfig);

public func pre_upgrade(){
    classConfig := MyClass.toStable()
};
1 Like

Hi Skilesare
I tried to adapt your code. But it didn’t work out. This works well on simple types, that is, on types that are part of motoko.base . I have a complex type, more precisely, the same class. When assembling into a canister, the dfx compiler writes the following: variable storage Config_st is declared stable but has a non-stable type

However, I will give a little code and explanations on the code
I have two classes
class Storage()
class Tree<K, V>()

in module:

public type StableConfigType = { tree : T.Tree<Text, Text>; };
public func default_config() : StableConfigType  {
    return {tree = T.Tree<Text, Text>("root", "root", null, ?List.nil<Tree>(), 0, 0, Text.equal, Text.hash);};
};

in actor:

stable var storageConfig: Storage.StableConfigType = Storage.default_config();

Classes will typically not be stable since they usually contain function types as members of the type.

See

and

Hi Claudio
Yes, I read it. I had a feeling that there might be hacks like c mutable/immutable array. Or statically, a reference to the initialized class is stored somewhere, which can be deployed after the update. I would like to finish this topic and not be distracted. Claudio do I understand correctly that the initialization of all classes occurs at the time of creating the canister and at the time of its update? That is, if you do not change the state of the canister from outside (creation, updating) and change only the internal structure by external calls, then its structure will be updated and preserved?

Safik,
Sorry, but I don’t really understand the question. Maybe if you could provide a small, concrete example, I could understand better.

let’s say there are classes:

public class clA(){//logic};
public class clB(){ let instanceA = clA(); //logic};
in actror
actor actC(){
let instanceB = module.clB();
//logic
};

When creating a canister or updating the canister code, the instancesA and InstanceB operands are explicitly initialized.

I can reset “instanceB”

actor actC(){
let instanceB = module.clB();
func reset_instances(){
instanceB := module.clB();
};
//logic
};

Can “instanceB” and “instanceA” be initialized (not intentionally)?

At the moment, my data structure is saved in the local version of the dfx sdk. Perhaps I will redo the logic of initializing variables. That is, they will be initialized not at the time of creating the canister or its update, but through function calls.

Thanks for the example. I think I may have marked it as a solution by mistake, apologies if so (I can’t see how to undo it)

As written, I think the instances will be reinstalled with fresh ids, leaking the old ones, when the enclosing canister is upgraded.

However, actor type are both shared and stable, so if you declared them a stable let’s or vars in the body of the actor (not a function) they would be preserved on upgrade and not reinstalled. The only problem is that you can’t actually send messages during the initialization so you’ll need to mark them stable but initialize them through a shared function call. You may need to make the fields option types for that though, or use a bogus actor reference as a dummy initializer and be sure not to use it until properly initialized.