Is Buffer.clone a deep clone?

If I have a Buffer of Buffers and I clone the parent Buffer, does it clone the buffers all the way down the buffer chain, or will my clone have pointers to the original child buffers?

Never mind…found it…looks like it is shallow:

 /// Returns a copy of this buffer.
    public func clone() : Buffer<X> {
      let c = Buffer<X>(elems.size());
      var i = 0;
      label l loop {
        if (i >= count) break l;
        c.add(elems[i]);
        i += 1;
      };
      c
    };

There is no generic way to clone values(*), so the buffer’s clone method necessarily has to be shallow. If you need a deep clone, you have to program it manually by iterating over the buffer and do whatever needs to be done for the elements explicitly.

(*) Nor must there be – the ability to externally clone e.g. an object would break encapsulation.

I wanted to validate some of my assumptions here so I put this quick bit of code together to verify that both standard types and variants are generally handled by value rather than by ref. I think it is the “class” distinction that moves something to a by val treatment to a by ref treatment. This may all make sense to most but I still have Visual Basic trauma that I’m dealing with.

https://m7sm4-2iaaa-aaaab-qabra-cai.raw.ic0.app/?tag=3465183483

Motoko is a sufficiently high-level language that there isn’t an observable difference between by-value vs by-reference. That’s an implementation detail entirely. The only thing that’s semantically visible is that a value containing a mutable member (e.g. a var field or var array element) is never implicitly copied.

FWIW, class is completely immaterial in that regard as well. It is merely syntactic sugar for a regular function that returns an object, plus a type definition.

3 Likes
type buffer = Buffer.Buffer<Types.Post>;
    var init : Nat = 0;
    var xchange : buffer = Buffer.Buffer<Types.Post>(init);
    for(curPost in mapxchange.vals()){
        xchange.add(curPost);
    };
    //getXchange function to return array of posts of single xchange.
    public query func getXchange() : async buffer{
        return xchange;
    };

Types.Post is a Entity and mapxchange is a hashmap of Types.Post (as Value)

Silly Doubt, but i am getting error in the return type of getXchange() function,
Error :shared function has non-shared return type

So, I want to ask is there any other way to return buffer , or i should return it as Array , using toArray() function?

Buffer is a mutable type. Mutable values are not sharable, i.e., they cannot be sent as arguments or results of actor messages. You’ll need to produce an (immutable) array.

1 Like

Just one more silly doubt :

public func putPost(newPost : Types.Post) : async (){
        var curPPID : Nat = newPost.ppid;
        if(curPPID == 0){
            //make new xchange with hospost as newPost
            var newXid : Nat = mapXchange.size() + 1;
            var newXchange : bufferPost = Buffer.Buffer<Types.Post>(0);
            newXchange.add(newPost);
            mapXchange.put(newXid, newXchange);
        };
        if(curPPID != 0){
            for(curXchange in mapXchange.vals()){
                var curXchangeArray : [Types.Post] = curXchange.toArray();
                if(curXchangeArray[0].xid == newPost.xid){
                    curXchange.add(newPost);
                };
            };       
        };
        return ();
    };

Above is a function to put a entity in a hashmap.
**Entity : hostPost **

let hostPost : Types.Post = {
        pid = 1;    // Post Id
        uid = 1;    // User Id
        ppid = 0;   // Parent Post Id, Null = no parent, so this is a hostPost
        xid = 1;    // Xchange Id
        tid = 0;    // Thread Id
        cid = 0;    // Conversation (= Discourse = Issue = Subject = Topic) Id)
        iid = 0;    // Instance Id
        did = 0;    // Debate Id
        postType = "Introduction";
        speakerName = "Carl";
        createdAt = "2021-05-22 07:56:09.282+00";
        summary = "Etiam imperdiet ullamcorper lorem. Integer ac nisi eget arcu.";
        details = "<div><p>Pellentesque accumsan risus ut fermentum hendrerit!</p>\n<p>Nulla ac velit lobortis, iaculis mauris et, suscipit orci. Quisque viverra sem in aliquet bibendum. Etiam sodales tincidunt turpis convallis hendrerit. Maecenas luctus fringilla ex, vel rhoncus leo lobortis et. Cras laoreet sit amet justo vel viverra!</p></div>";
        thumbnail = "";
        titleFrame = "";
        votable = true;
        voteType = "resonate";
        video = "hd9dwdbd8xv";
        published = true;
    };

But when i am trying to call this function in terminal to put above entity in hashmap , it is showing some syntax error.
Can you please correct this?

dfx canister call canisterName putPost hostPost

Error :Invalid argument: Invalid Candid values: Candid parser error: Unrecognized token Id("hostPost") found at 0:8
Expected one of “(”, “blob”, “bool”, “decimal”, “float”, “func”, “hex”, “null”, “opt”, “principal”, “record”, “service”, “sign”, “text”, “variant” or "vec"

Answered in your new thread here: https://forum.dfinity.org/t/syntax-error-in-terminal-function-call/11268/2?u=ori

so does it means that i cannot pass it as a single entitiy, and i have to pass it in the same way everytime?
And this way also not working.