Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

The set macro is linking two objects together permanently

I am using SugarCube 2.7.2 on Twine 2.0.11

I've narrowed down my error to this odd 'feature'/bug, and recreated it in a fresh story.
<<set $First to {A: 0, B: 0}>>

<<set $Second to $First>>

<<set $Second.A to 1>>

$First.A
$First.B

$Second.A
$Second.B

This is the only thing this story contains.

The output from this passage is:

1
0

1
0

$First.A is set to 1, and I cannot see why.

If I move the line "<<set $Second.A to 1>>" to another passage, $First.A remains 0.

Am I going crazy? Or is this a bug/'intended feature' in either Twine or SugarCube?

Comments

  • When you assign an object to a variable the value stored in the variable is not the object itself, it is a reference to the object. (known as an object reference)

    When you do the following <<set $Second to $First>> within the same passage as the initial assignment you are assigning the object reference stored in the First variable to the Second, so now both variables are referencing the same object and any changes to that object effect both variables.

    This behaviour changes after traversing to a new passage because during the traversal the current state (values) of all the known variables is copied and it is this copy which is made available to the next passage being shown. The copy procedure causes any variables that were referencing the same object to each now reference their own new copies of the original object, the new copies have the 'same value' as the the original.
  • It seems counter-intuitive to me, but I think I understand. Thank you.

    Is the solution therefore to have some form of initialisation/startup passage as the starting point of your story, with the sole purpose of establishing every variable you use and 'locking' them in by traversing to a new passage? And avoid assigning one object to another and editing the latter object in the same passage.
  • Another question: how does the <<display>> macro come into play with this?

    I found a second instance of this issue. I tried to fix it by isolating the change in $Second.A in another passage. In simplified terms, the following is happening:
    ::Passage One
    <<set $First to {A: 0, B: 0}>>
    <<set $Second to {}>>

    [...]

    ::Passage Two
    <<set $Second to $First>>
    <<display "Passage Three">>

    ::Passage Three
    <<set $Second.A to 1>>

    This produces the same result as in my OP. If <<display is changed to <<goto. this one problem is solved, but that workaround causes a whole host of other issues regarding my story structure. Is there a better solution?
  • As explained by greyelf, the variable store is copied during passage navigation. The <<display>> macro does not trigger passage navigation, it simply includes the given passage.

    If you want to make copies of simple generic objects, you may use the JavaScript native Object.assign() method. For example:
    <<set $First  to {A: 0, B: 0}>>
    <<set $Second to Object.assign({}, $First)>>
    
  • Thanks. I'd assumed the display macro wasn't triggering passage navigation from that attempt at a solution, the confirmation is useful. And the Object.assign() method has solved this issue perfectly, so thanks to both of you for your help.

Sign In or Register to comment.