Do not comprehend "Ref" objects

Get help using and writing Nisus Writer Pro macros.
Post Reply
User avatar
phspaelti
Posts: 1005
Joined: 2007-02-07 00:58:12
Location: Japan

Do not comprehend "Ref" objects

Post by phspaelti » 2018-10-26 17:47:39

I decided I would try some testing to get a better understanding of the new "Ref" objects in NWP 3.0. So I tried the following:

Code: Select all

$values = "123456789"
$grid = $values.split('')
$cell = Ref.new($grid[3])
prompt $grid, $cell.value
$grid[3] = "25"
prompt $grid, $cell.value
Imagine my surprise when I got the following result:
Ref.png
Ref.png (16.18 KiB) Viewed 2754 times
I can't really make any sense of this. I thought the whole point of a Ref was to point at the object, rather than copy the value, which in my understanding should mean that it tracks changes made to the object later. Does

Code: Select all

$grid[3] = "25"
really create a brand new text object and leave the prior "4" stranded? :?

I also tried changing $grid[3] = "25" to $grid[3] &= "25" (with the idea that there might be difference between "new assignment" and "modifying an existing value"), but the result was no different.
philip

User avatar
phspaelti
Posts: 1005
Joined: 2007-02-07 00:58:12
Location: Japan

Re: Do not comprehend "Ref" objects

Post by phspaelti » 2018-10-26 18:21:14

After writing the above, I guess I'm going to try to answer my own question.

Presumably NWP text objects are immutables, and an array is (something like) a linked list. So every change to a text object really does create a brand new object and the linked list is just updated to have its (in this case 4th) item point to the new object. The Ref object keeps pointing at the original text object.

I'll have to mull over this some more :drunk:
philip

martin
Official Nisus Person
Posts: 4545
Joined: 2002-07-11 17:14:10
Location: San Diego, CA
Contact:

Re: Do not comprehend "Ref" objects

Post by martin » 2018-10-30 09:54:04

Before we get too deep into Refs, I'd like to repeat what's said in the Nisus Writer Macro Reference:
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.
That's for the benefit of anyone else reading this discussion, as generally you don't need to use or know about Refs when writing macros.
Presumably NWP text objects are immutables, and an array is (something like) a linked list. So every change to a text object really does create a brand new object and the linked list is just updated to have its (in this case 4th) item point to the new object
That's functionally correct at least as far as the array is concerned (though arrays aren't necessarily implemented as linked lists). Your array assignment statement ($grid[3] = "25") is merely changing the array itself. Your code doesn't access or modify the Ref you created.

Here's an example that helps show the difference between using a Ref and not:

Code: Select all

$text = "hello"
$modified = $text		# the text is copied
$modified.append("!")
Prompt $text, $modified		# "hello" and "hello!"

$text = "hello"
$modified = Ref.new($text)	# use Ref to prevent copy
$modified.value.append("!")
Prompt $text, $modified.value	# "hello!" and "hello!"
The top part of the code actually uses two Text objects. A copy is implicitly made during the assignment of the $modified variable.
The bottom part of the code sidesteps the copy by wrapping the Text object in a Ref.

That example is of course very contrived. You're more likely to use Refs if you need to pass objects around to custom commands (user defined functions). The macro reference goes into some detail describing why you might want to use Refs to wrap hashes or arrays, so they aren't copied as you pass them around between functions.

Text objects are also somewhat special in that they inherently sometimes use value semantics and other times use reference semantics. This is described in the macro reference's Text object documentation under "Storage Semantics". This is potentially confusing when trying to understand the inner workings of macros, but generally behaves correctly when you consider how text objects can originate differently. Some text objects are unique and it's less likely that you want to copy them and thus should use reference semantics (eg: a document's main text object), while other text objects are anonymous and ephemeral like the example string "hello" and thus should generally be copied.

Text objects that already use reference semantics don't need to be wrapped in a Ref. For those text objects you actually have the opposite problem: you might need to force an explicit copy if you don't want to modify the original text, eg:

Code: Select all

$doc = Document.active
$text = $doc.text
$independent = $text.copy
$independent.append("!")	# does not modify the document's text 
I hope this helps clarify the use of Ref at least a little bit. Please let me know if you have any more questions.

Post Reply