<- PRPL reference <- Lists

CopyList vs DeepCopyList vs dup / just passing the list

When you have a list in a variable for example, and you need to use the list in a function for example, you might not know whether to just pass the list into the funtion (<-myList @myFunction), use CopyList (<-myList CopyList @myFunction) or whether to use DeepCopyList (<-myList DeepCopyList @myFunction). In this article, you will learn the benefits and dangers of each.

Lists are the only mutable data type in PRPL

All other data types in PRPL (int, float and string) are immutable, that means that they never change their value. If you have number 5 stored in a variable x and call <-x 1 add ->x, you don't change the number 5 itself, you change the content of variable x from 5 to 6.

Same with strings. If you call <-myString “e” “a” StringReplace ->myString you don't change the string itself that is stored in myString, you change which string is stored in myString. (If this doesn't make any sence to you, don't worry, the distinction will become clearel once we get to some examples with lists.)

However, with lists it's different. If you have a list stored in a variable myList and call <-myList “foo” AppendToList you are actaully changing the list stored inside the variable myList. You can, of course, still change which list is stored in a variable by calling CreateList ->myList for example. However, the fun becomes when the same list is stored in different varaibles.

Sharing list in multiple variables (or on stack)

Let's start by a quick example with 3 lists and 4 variables: (I have named the lists ListA,B,C so that we can keep track of which variable has which list stored in it)

"a,b,c" "," Split ->list1 #ListA
"a,b,c" "," Split ->list2 #ListB
<-list1 ->list3           #ListA
"x,y,z" "," Split ->list4 #ListC
 
<-list1 Trace # ["a", "b", "c"] #ListA
<-list2 Trace # ["a", "b", "c"] #ListB
<-list3 Trace # ["a", "b", "c"] #ListA
<-list4 Trace # ["x", "y", "z"] #ListC

This would make it seem that all the 3 variables list1,2,3 contain the same list, but they don't. list1 and list3 contain the same list, however list2 contains a different list, although with the same content as the list stored in list1 and list3.

If we change list1, list3 will be change as well, because it is the same list, just stored inside 2 different variables:

<-list1 2 "foo" SetListElement    #ListA
<-list1 Trace # ["a", "b", "foo"] #ListA
<-list2 Trace # ["a", "b", "c"]   #ListB
<-list3 Trace # ["a", "b", "foo"] #ListA
<-list4 Trace # ["x", "y", "z"]   #ListC

However, if we change which list is stored inside the list1 variable, list3 will remain the same:

<-list4 ->list1                   #ListC
<-list1 Trace # ["x", "y", "z"]   #ListC
<-list2 Trace # ["a", "b", "c"]   #ListB
<-list3 Trace # ["a", "b", "foo"] #ListA
<-list4 Trace # ["x", "y", "z"]   #ListC

Now, the variables list1 and list4 contain the same list, and if we called <-list1 “boo” AppendToList for example, it would change list4 as well, because AppendToList changes the list itself, and list4 now contains the same list as list1.

Finally we get to use (Deep)CopyList

So, what if we didn't want 2 variables sharing the same list, but instead wanted to copy the list from one variable into another so that we can then change eighter list without affecting the other one? Well, that's exactly what CopyList is for. It creates a new list, but with the same contents.

"x,y,z" "," Split ->list1
<-list1 CopyList ->list2
 
<-list1 2 RemoveListElement
<-list1 Trace # [ "x", "y" ]
<-list2 Trace # [ "x", "y", "z" ]

And that's prety much it. DeepCopyList is for when the list being copied contains another lists as it's elements, so that even those lists gets copied instead of being shared. For even more datailed explanation with pictures, check out How are lists implemented.