Ref Object

(The Ref object was added in v3.0)

By default variable assignments are done by value. That is, the value is copied during assignment so it’s independent from the original value. Sometimes this is undesirable, and you instead want to assign by reference. To do that you use a Ref object to wrap the original value.

A Ref object may be used interchangeably with its original value in any situations where the original type is expected. If some code expects an array, you can instead use a Ref to an array, eg:

$colors = Array.new("red", "green", "blue")

$arrayRef = Ref.new($colors)

Prompt Checkboxes "Pick some colors:", "", "Okay", $arrayRef

You may also use a Ref to an array or hash in loops:

$colors = Array.new("red", "green", "blue")

$arrayRef = Ref.new($colors)

ForEach $color in $arrayRef

Prompt $color

End

Generally you do not need to use Ref objects. They are mostly useful only when your macro is running slowly because it’s unnecessarily copying arrays or hashes, or when dealing with nested data structures. See the examples section below.

Ref Type Commands

Ref.new value v3.0

Returns a new Ref object that holds a reference to the given macro value. The value cannot be a primitive type like an integer or float, but should be an object type like an array, hash, or text object.

Ref.null v3.0

Returns a Ref object representing NULL (a Ref without a referenced value).

Ref Object Properties

.value v3.0

The value being referenced.

Ref Object Examples

If your macro is running slowly it may be due to the hidden cost incurred when implicitly copying arrays or hashes during variable assignments. This can occur if you have very large arrays or hashes, or assign them frequently. Here’s an example that runs very slowly:

Debug.setCodeProfilingEnabled @TRUE

$groupedNums = Array.new

For $ii = 0 to 55000

$remainder = $ii % 10

If $remainder >= $groupedNums.count

$numbers = Array.new

Else

$numbers = $groupedNums[$remainder]

End

$numbers.appendValue($ii)

$groupedNums[$remainder] = $numbers

End

If you run the above code chunk it will take a long time. Can you see why? The problem is that the array is implicitly copied each time through the loop for the following line:

$groupedNums[$remainder] = $numbers

That means an array of numbers is copied each time through the loop, even as it gets bigger and bigger. This incurs an exponential cost as the number of loop iterations rises. To fix the problem we can use a Ref to capture a reference to a single array, preventing it from being copied:

Debug.setCodeProfilingEnabled @TRUE

$groupedNums = Array.new

For $ii = 0 to 55000

$remainder = $ii % 10

If $remainder >= $groupedNums.count

$numbers = Array.new

$numbersRef = Ref.new($numbers)

$groupedNums[$remainder] = $numbersRef

Else

$numbersRef = $groupedNums[$remainder]

$numbers = $numbersRef.value

End

$numbers.appendValue($ii)

End

The above code runs in a fraction of the time required by the original.

In addition to preventing unnecessary value copying, Refs can also be used to maintain more complicated data structures. Here’s an example that behaves incorrectly due to value semantics:

Define Command AppendToArrayInHash( $hash, $key, $addValue )

$list = $hash{$key}

If ! $list

$list = Array.new # set initial empty array

$hash{$key} = $list

End

$list.appendValue($addValue)

End


$foodMap = Hash.new

AppendToArrayInHash( $foodMap, "fruits", "apple" )

AppendToArrayInHash( $foodMap, "fruits", "banana" )

AppendToArrayInHash( $foodMap, "veggies", "carrot" )

Prompt $foodMap

The above example doesn’t add any values to the arrays in the hash. The array $list is independent from the array stored by the Hash because a copy is made each time the variable is assigned. 

To fix this we need to capture and store a Ref to the array.

Define Command AppendToArrayInHash( $hash, $key, $addValue )

$listRef = $hash{$key}

If $listRef

$list = $listRef.value

Else

$list = Array.new # set initial empty array

$listRef = Ref.new($list)

$hash{$key} = $listRef # store a Ref to prevent copying

End

$list.appendValue($addValue)

End


$foodMap = Hash.new

AppendToArrayInHash( $foodMap, "fruits", "apple" )

AppendToArrayInHash( $foodMap, "fruits", "banana" )

AppendToArrayInHash( $foodMap, "veggies", "carrot" )

Prompt $foodMap


Previous Chapter
Rect Object
<<  index  >>
 
Next Chapter
Shadow Object