How to copy an array of Objects instead of referencing

I ran into an issue today, which drove me mad. Assigning one array to another does not copy/clone it, instead, it makes a reference, which is fine; However, I could not find a single way to Clone arrays of objects. Do I have to manually re-construct objects of a class every time I want to copy an array of objects?

Am I crazy? Please tell me I am crazy, and there is an easy and obvious way to do this in Verse.

object := class<concrete>:
    @editable
    var Value: int = 0

bug_finder := class(creative_device):

    @editable
    # Defined in editor as 7, 8, 9
    ArrayOfObj: []object = array{}

    OnBegin<override>()<suspends>:void=
        var LocalArrayOfObj1: []object = ArrayOfObj
        var LocalArrayOfObj2: []object = ArrayOfObj
        
        for (Item : ArrayOfObj):
            Print("(Before Assigment) Original: {Item.Value}")

        if (Item := LocalArrayOfObj1[1]):
            set Item.Value = 1

        for (Item : LocalArrayOfObj1):
            Print("LocalArrayOfObj1: {Item.Value}")

        for (Item : LocalArrayOfObj2):
            Print("LocalArrayOfObj2: {Item.Value}")

        for (Item : ArrayOfObj):
            Print("Original: {Item.Value}")

image

sounds like you need some sort of copy constructor

Another example, I understand now that Classes are not copied and always are a reference, but this behaviour still does not feel right to me as a Default.

Now that I know that, I can work around it, but it probably needs to be stated in the docs.

Works as advertised. Arrays are always copied and not referenced. If you create a copy of an array and delete an element, the deletion won’t happen on the origin array. Everything is fine there.

You must understand the difference between reference types and value types as well as reference and value semantics, while the latter is not relevant here.

Class is reference type, so is theoretically a function as well. A struct, enum, (union), tuples, and other primitive types are all value types. Value type instances are copied around while reference type instances creating a copy of the reference to their object.

You have to rethink your design if you want a fresh copy. Classes won’t ever change that behavior as this is by common design.

4 Likes

Can you point me to the documentation where it says arrays are passed by copy? I thought I observed some behaviour that lead me to think they pass by reference but was apparently wrong.

Ok I see where my confusion was now. You can have mutable arrays e.g. var Arr: []int, but when that’s passed to a function it become immutable (unless there is a way to annotate in the function signature that it is mutable I don’t know about).

In Swift for example that would be an inout parameter. It it passes still a copy (in case of value types), but allows you to mutate it as it was a variable and it will write it back to the original variable when the execution of that function call ends. Verse does not have such capabilities yet.

It’s the same if you took a an array which is stored in a variable and assigned that to a new variable. Regardless of both being variables, changing the second one will not cause any updates on the original one.

However, I will write a single example in short just to confirm that the passed value isn’t just a pointer to the original one. Just bumped over pointers in the docs and got curious.

Thanks, Good to know re. assigning a var array. I was likely influenced by my TypeScript knowledge where arrays are more like a C# List class and treated like a generic object reference.

hello_world_device := class(creative_device) {
  var Array: []int = array { 42 }

  OnBegin<override>()<suspends>: void = {
    Print("Test")
    sync {
      Mutator()
      Reader(Array)
    }
    Print ("Done")
  }

  Mutator()<suspends>: void = {
    Print("Starting mutator"
    Sleep(1.0)
    Print("Resumed mutator") 
    set Array = array { 0 }
    Print("Finished mutator")
  }

  Reader(A: []int)<suspends>: void = {
    Print("Starting Reader")
    Sleep(3.0)
    Print("Resumed Reader")
    for (E: A) {
      Print("Element from A: {E}")
    }
    for (E: Array) {
      Print("Element from Array: {E}")
    }
    Print("Finished Reader")
  }
}

<# OUTPUT:
LogVerse : Test
LogVerse : Starting mutator
LogVerse : Starting Reader
LogVerse : Resumed mutator
LogVerse : Finished mutator
LogVerse : Resumed Reader
LogVerse : Element from A: 42
Logverse : Element from Array: 0
LogVerse : Finished Reader
LogVerse : Done
#>
2 Likes

This is what I ended up doing based on feedback here, thank you everyone for the help!

### Implementation
object := class<concrete>:
    @editable
    var Value: int = 0
    
# Clone object
(Object:object).Clone():object=
    return object{Value := Object.Value}

# Clone array of object
(Object:[]object).Clone():[]object=
    var TmpArray: []object = array{}
    for(Obj : Object):
        set TmpArray += array{Obj.Clone()}
    return TmpArray

### Use Case
var LocalArrayOfObj1: []object = ArrayOfObj.Clone()
var LocalArrayOfObj2: []object = ArrayOfObj.Clone()	
2 Likes

I think this article will be useful for you.

1 Like

Hi. I think your code can be simpler.

# Clone array of object
(Object:[]object).Clone():[]object=
    for:
        Obj:Object
    do:
        Obj.Clone() #return value