Roku Developer Program

Join our online forum to talk to Roku developers and fellow channel creators. Ask questions, share tips with the community, and find helpful resources.
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
parag
Visitor

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 11
NB_
Roku Guru

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
Visitor

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
NB_
Roku Guru

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
Visitor

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
NB_
Roku Guru

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
Visitor

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
NB_
Roku Guru

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
Visitor

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
Visitor

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
Need Assistance?
Welcome to the Roku Community! Feel free to search our Community for answers or post your question to get help.

Become a Roku Streaming Expert!

Share your expertise, help fellow streamers, and unlock exclusive rewards as part of the Roku Community. Learn more.