Howdy, Stranger!

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

Set between two variables.

What is the behaviour when you set a variable to another variable? I am using Sugarcube 2.

Say I have $array which is an array of characters and I go:

<<set $array[0].name to "foo">>
<<set $char to $array[0]>>
<<set $char.name to "bar">>

Will &array[0].name now be foo or bar? It seems to be very inconsistent, with the value sometimes retroactively updating and sometimes not. Is there some update mechanism which triggers in specific situations?

Thanks!

Comments

  • Your example is assigning the object reference value stored in the first element of your $array array variable to the $char variable, this results in both variables referencing the same object.

    What happens when you update an attribute of the referenced object depends if that update is done in the same navigable passage as the object reference assignment or not.

    1. Attribute update is done is same navigable passage as the object reference assignment:

    Because both variables are reference the same object then the update effects both.
    <<set $array to [{name: ""}]>>\
    <<set $array[0].name to "foo">>\
    <<set $char to $array[0]>>\
    <<set $char.name to "bar">>\
    \
    array name: <<print $array[0].name>>
    char name: <<print $char.name>>
    

    2. Attribute update is not done is same navigable passage as the object reference assignment:

    Each time the reader navigates (forward) between passages a copy of all known variables is created and it is that copy which is made available to the next passage, this is done so that the History system can undo the navigation.

    This copying process results in variables that were referencing the same object to now each be referencing their own copy of the original object.

    2a. First passage:
    <<set $array to [{name: ""}]>>\
    <<set $array[0].name to "foo">>\
    <<set $char to $array[0]>>\
    <<set $char.name to "bar">>\
    \
    array name: <<print $array[0].name>>
    char name: <<print $char.name>>
    
    [[Next Passage|Second]]
    

    2b. Second passage:
    <<set $char.name to "bas">>\
    \
    array name: <<print $array[0].name>>
    char name: <<print $char.name>>
    
  • edited October 2016
    So, in C pseudocode, when i set $char to $array[0], Twine actually passes $array[0] by reference:
    var* char = &array[0]
    

    So char and array[0] are in fact identical pointers. However, when I move between passages, Twine does
    var* charNew = &[contents of char]
    var* arrayNew = &[contents of array]
    

    And it's this charNew and arrayNew that is used in the new passage, so now they're pointing to distinct objects, copies of what they originally referenced.

    Is that sort of what you meant, as far as end user functionality is concerned?
  • edited October 2016
    tonyxc600 wrote: »
    ...Twine does...
    Not the Twine application as that is just a passage (Markup, Javascript, CSS) editor and story HTML file compiler, it is your chosen Story Format that is doing everything because it is a Javascript based web-application that knows how to dynamically process the contents of your story's passages.
    tonyxc600 wrote: »
    So, in C pseudocode...
    Is that sort of what you meant...
    Yes.

    I used a less technical explanation because there is no way of knowing the technical level of the person asking a question, nor of the others that may read this topic later. *smile*
  • edited October 2016
    I used a less technical explanation because there is no way of knowing the technical level of the person

    And the explanation was very clear, I just wanted to double check. Much appreciated!

    Before I mark this as closed, does this behaviour only apply to objects, or to all variables such as numbers/strings? Also, is there any way to create a 'true' copy of an object within the same passage? That would be very convenient in some cases :blush: :

    Thanks!
  • tonyxc600 wrote: »
    does this behaviour only apply to objects, or to all variables such as numbers/strings?
    It only applies to complex object types.
    tonyxc600 wrote: »
    is there any way to create a 'true' copy of an object
    Use the SugarCube clone() function.
  • tonyxc600 wrote: »
    […] does this behaviour only apply to objects, or to all variables such as numbers/strings?
    Pass-by-reference behavior applies to all reference types. In JavaScript, you have two basic type categories: value types (a.k.a. primitive types) and reference types (i.e. objects).

    Value types have pass-by-copy semantics and are primitives like: numbers (incl. both integer and floating-point), strings, booleans, symbols, and the two special values: null and undefined.

    Reference types have pass-by-reference semantics and are objects. In JavaScript, every data type which is not a value/primitive type is an object at heart—this includes arrays and functions/methods.

    Suggested reading (from the Mozilla Developer Network (MDN)):
    FYI. Each value/primitive type, save for null and undefined, also have an associated object, which is where the types' methods are stored. For example: numbers have Number, strings have String, and so on. Do not confuse the value type with its associated object. Also, as a general rule, never use the constructor for the associated object of a value type as a constructor—calling it with the new keyword—to create a new instance of the type—use its literal notation instead. For example:
    → GOOD
    <<set $foo to "Snarf">>  → Returns a string primitive
    <<set $bar to 42>>       → Returns a number primitive
    <<set $baz to 3.14>>     → Returns a number primitive
    <<set $qaz to true>>     → Returns a boolean primitive
    
    → BAD
    <<set $foo to new String("Snarf")>>  → Returns a String object
    <<set $bar to new Number(42)>>       → Returns a Number object
    <<set $baz to new Number(3.14)>>     → Returns a Number object
    <<set $qaz to new Boolean(true)>>    → Returns a Boolean object
    
    That said you may call the constructor for the associated object of a value type without the new keyword—basically calling it as a simple function, rather than as a constructor—to do type conversions. You probably won't do this very often, as implicit type coercion is a thing and there are other ways to do explicit type conversions, however, it can occasionally be useful. For example:
    → TYPE CONVERSION
    <<set $foo to String(747)>>     → Returns the string primitive "747"
    <<set $bar to Number("42")>>    → Returns the number primitive 42
    <<set $baz to Number("3.14")>>  → Returns the number primitive 3.14
    

    tonyxc600 wrote: »
    Also, is there any way to create a 'true' copy of an object within the same passage?
    As greyelf mentioned, the clone() function, which returns a deep copy of the original. Be sure to read its documentation to learn of its limitations—it does not support every native object type that JavaScript offers.
  • Thanks you, the detailed explanation is much appreciated. You guys are lifesavers!

    I may be blind, but I can't find the button to mark thread as answered. If this is an mod only thing please go ahead, if not please point me the right way :smile:
  • Did you create the topic as a Question or a Discussion? Because you can't mark the later as Answered.
Sign In or Register to comment.