Roku Developer Program

Developers and content creators—a complete solution for growing an audience directly.
cancel
Showing results for 
Search instead for 
Did you mean: 
Highlighted
parag
Level 7

Copy of Brightscript object being created when using assignment operator.

In my main.brs, I am parsing a JSON from server and then assign the result which is an associative array with more nested associative arrays which house more arrays.

json = ParseJSON()
m.scene.json = json

Now, what I would expect is that it m.scene.json should be a reference to json since it is not an intrinsic object and not a copy, but a copy is being created. Any changes I make to 'json' now don't show up in m.scene.json and hence my assumption that it is a copy and not a reference. Also, after the assignment, m.scene.json become immutable and any additions that I make to the associative array fail silently.

Any ideas what I am doing wrong and what I should be doing instead?
0 Kudos
11 Replies
Roku Employee
Roku Employee

Re: Copy of Brightscript object being created when using assignment operator.

RSG thinks different than Brightscript.
dot-access for nodes (i.e. myNode.myField) gets converted to a setValue/getValue call (depending on which side of assignment that is) and these i think always assign composite objects like roAssociativeArray and roArray "by value", in result doing deep-copy for your JSON. Nodes are assigned by reference.

When you do
m.scene.json.a = 7
the m.scene gets the node, m.scene.json returns a deep copy of the dictionary, then .a = 7 adds/assigns a key-value pair - but this is a different copy that gets modified. At the end of that statement, this copy gets disposed since nobody needs it anymore - the original m.scene.json however remains unmodified (hence "read-only")
0 Kudos
parag
Level 7

Re: Copy of Brightscript object being created when using assignment operator.

Thank you for your prompt response. It does clear why I seemingly had an immutable copy. But, how do I go about making changes which are persisted? Would it make sense to parse the JSON inside a new task and then assign it to the scene, but I am assuming that I will end up at the same place.

Also, if I am in the node and try to access json using m.top.json, would I get a copy again as opposed to the reference because that is what is happening currently.
0 Kudos
Roku Employee
Roku Employee

Re: Copy of Brightscript object being created when using assignment operator.

The response i have heard has been to use ContentNodes instead, i.e. rebuild your structure using ContentNode (or even Node if no media metadata) as a foundation for your nested structures. And that makes total sense if the data you have is either (a) multimedia item info or (b) will be used for RSG API calls (most components ask for their collections in ContentNode form).

Note that Node (roSgNode) components are passed by reference because of multi-thread-safe mechanism in them. So if convenient, their use is more efficient than deep copies.

Also note that inside a component script you could (and probably should) use the self/this variable `m` to store and mutate complex {}/[] structures.
0 Kudos
parag
Level 7

Re: Copy of Brightscript object being created when using assignment operator.

So, if I am getting this correctly, I should use a ContentNode for a field in the scene. Would that be different from using associative array? Would that not be immutable? Or am I completely off base?

To add to the above question, I tried the following sequence of steps

HomeScene.xml

<component name="HomeScene" extends="Scene"  xsi:noNamespaceSchemaLocation="https://devtools.web.roku.com/schema/RokuSceneGraph.xsd">
   <interface>
       <!-- <field id="json" type="assocarray" /> -->
    <field id="json" type="node" />


In main.brs

    m.scene.json = createObject("roSGNode", "ContentNode")

    m.scene.json.addFields({title: json.reftitle, contentList:json.contentList, backgroundUrl:json.backgroundUrl})


ContentList is an roArray type. So, while I can change the title, I can't make any changes to for ex the title field in the associative array in the ContentList array or add another item to the array. Should all the hierarchical components if they are not of intrinsic types be a ContentNode? Thanks.
0 Kudos
Roku Employee
Roku Employee

Re: Copy of Brightscript object being created when using assignment operator.

"parag" wrote:
So, if I am getting this correctly, I should use a ContentNode for a field in the scene. Would that be different from using associative array? Would that not be immutable? Or am I completely off base?
[...]
ContentList is an roArray type. So, while I can change the title, I can't make any changes to for ex the title field in the associative array in the ContentList array or add another item to the array. Should all the hierarchical components if they are not of intrinsic types be a ContentNode? Thanks.

Using Node or ContentNode field to hold your data is different that using roAA/roArray in that yes, from your point of view node fields are mutable "in place". And yes, if you want to modify your complex structures in place, you should use Node/ContentNode instead of roAA/roArray. Would it help if in the context of node fields only you think about arrays/dictionaries as "by value" primitive types - and all roSgNode subtypes as "by reference" objects?

Why are you not using the component's `m` variable? Is it because you want to mutate a complex structure from outside?
0 Kudos
parag
Level 7

Re: Copy of Brightscript object being created when using assignment operator.

"RokuNB" wrote:
"parag" wrote:
So, if I am getting this correctly, I should use a ContentNode for a field in the scene. Would that be different from using associative array? Would that not be immutable? Or am I completely off base?
[...]
ContentList is an roArray type. So, while I can change the title, I can't make any changes to for ex the title field in the associative array in the ContentList array or add another item to the array. Should all the hierarchical components if they are not of intrinsic types be a ContentNode? Thanks.

Using Node or ContentNode field to hold your data is different that using roAA/roArray in that yes, from your point of view node fields are mutable "in place". And yes, if you want to modify your complex structures in place, you should use Node/ContentNode instead of roAA/roArray. Would it help if in the context of node fields only you think about arrays/dictionaries as "by value" primitive types - and all roSgNode subtypes as "by reference" objects?

Why are you not using the component's `m` variable? Is it because you want to mutate a complex structure from outside?

I am using 'm', but also want to mutate the structure from outside. What I have is a json containing a list of groups and each group has a list of videos. So, the HomeScene in this case has the parsed JSON (m.scene.json) and now when the user clicks on a video, I display the video details with a Play button. When user clicks on Play, I start playing the video, but I also want to add the video reference/details to the 'Recents' section in the parsed JSON which is where I am having trouble since my parsed copy is now immutable.
Also, if I am using Node/ContentNode, am I correct in assuming that anything that I want to stay mutable in the nested structure which is not an intrinsic type should also be a Node/ContentNode?
0 Kudos
Roku Employee
Roku Employee

Re: Copy of Brightscript object being created when using assignment operator.

"parag" wrote:
Also, if I am using Node/ContentNode, am I correct in assuming that anything that I want to stay mutable in the nested structure which is not an intrinsic type should also be a Node/ContentNode?

That's what i said - yes.
You can work around (of sorts) to that if you really, really want to by re-assigning the whole array/dictionary after every modification. Just keep in mind that's a deep copy and expensive. E.g. something like:

myJson = m.top.mySomeAssocArray ' deep copy '
recents = myJson.recent ' no deep copy, mutating this affects the source '
recents.push(newMovie)
if recents.count() > 20 then recents.shift() ' keep it trimmed down '
m.top.mySomeAssocArray = myJson ' set it back, another deep copy '
0 Kudos
parag
Level 7

Re: Copy of Brightscript object being created when using assignment operator.

Got it. Probably not the best idea to be copying large objects. Will try it to see that it does what I am expecting it to and then change all non-intrinsic objects to content nodes. Thanks again for your help. I might still have some more questions, but hopefully, I should be able to take it from here.
0 Kudos
parag
Level 7

Re: Copy of Brightscript object being created when using assignment operator.

Can I replace an array or list with a node/ContentNode? I have got most of it working, except I am still copying the array and would like to use a reference instead.
0 Kudos