Re: Coercing a list to string (nasty behaviour IMHO)
Re: Coercing a list to string (nasty behaviour IMHO)
- Subject: Re: Coercing a list to string (nasty behaviour IMHO)
- From: Nigel Garvey <email@hidden>
- Date: Wed, 29 Aug 2001 00:59:04 +0100
Axel Luttgens wrote on Sun, 26 Aug 2001 23:34:54 +0200:
>
Well, this is a point that always puzzled me in AppleScript (could perhaps
>
be
>
worth another thread: "What exactly is a reference in AS?").
I've asked this question here myself before now! (With very few replies,
it must be said.) :-)
>
I tend to believe that as soon as you can do something like this:
>
>
on f(Y)
>
set item 1 of Y to 1
>
end f
>
set X to {5, 6}
>
f(X)
>
log X
>
--> {1, 6}
>
>
you are working on a reference: using a classical terminology, Y must be a
>
pointer and not a list passed by value.
Y is a local copy of X, which is indeed a pointer to the list. Thus when
you change an item of Y, you also change that item of X. It's the very
same list. Only the pointers are copies. They both indicate the same
memory location. But, for some reason, AppleScript doesn't talk about its
"pointers"; we just say that the value of Y is the list, or that Y
"shares data" with X.
AppleScript "references" are something different. I don't understand how
they work internally, but they're *expressions* that are used in commands
to describe objects - or as objects in their own right. For example:
set w1 to the front window
--> the value of w1 is (say) 'window "Fnibble" of application "myApp"',
which happened to be in front when w1 was set. If Fnibble goes to the
back, w1 will still refer to it.
set w1 to a reference to the front window
--> the value of w1 is 'window 1 of application "myApp"'. Whatever the
front window may be in future, w1 will refer to it.
References can also refer to items that don't exist (though of course
you'll get some odd results if you try to dereference them):
set a to a reference to fred
-- *Now* define fred
set fred to {1, 2}
a as string
--> "12"
Normally the use of references in a script is transparent, but apparent
ambiguities do sometimes occur.
item 1 of {3, 4} = 3
--> true
{item 1 of {3, 4}} = {3}
--> false. The list on the left contains a reference, the list on the
right contains an integer.
>
So, if I sligthly rewrite example 1 as follows:
>
>
-- Example 1bis
>
on f(Y)
>
log {1, Y, 2000} as string
>
end f
>
set X to {7, 8}
>
f(X)
>
--> 1782000
>
>
it more clearly appears that I am performing a string coercion of a list
>
containing a reference.
Y isn't a reference; it's a pointer. The list {1, Y, 2000} consists of
pointers to the integer value 1, the list array {7, 8}, and the integer
value 2000. The values pointed to are all coercible to string and so '{1,
Y, 2000} as string' succeeds.
>
I insist :-)
>
There must be an evaluation:
>
>
-- Example 3bis
>
set X to {5, 6}
>
set Y to {7, 8}
>
set Z to {X, Y}
>
set item 1 of X to 9
>
log {1, Z, 2000} as string
>
--> "196782000"
>
>
If Z had been assigned value {{5, 6}, {7, 8}} by running the first three
>
lines,
>
4th line would not have been able to change that value.
>
I'm of the opinion that the interpretor evaluates Z when it encounters that
>
symbol in 'log {1, Z, 2000} as string', and only at that moment. Before that
>
moment, Z is just known to be a list of two variables (that could be
>
anything;
>
hence the recursive evaluation capability).
When you set X to {5, 6}, its value (as we've discussed) is a pointer to
the list {5, 6}. That list is itself an array of two pointers, one of
which points to the value 5, stored somewhere in memory, and the other of
which points to the value 6. A similar situation applies when you set Y
to {7, 8}.
When you set Z to {X, Y}, its value is also a pointer to an array of
pointers. One of these pointers is a copy of the pointer X and the other
is a copy of the pointer Y. This means that the lists pointed to by X and
Y are now also pointed to by the pointers in the array pointed to by Z.
Those lists are structurally items of Z:
--> {{5, 6}, {7, 8}}
As the first item of Z *is* the list pointed to by X, changing the first
item of X *is* changing the first item of (the first item of Z):
--> {{9, 6}, {7, 8}}
When Z is coerced to string, it's Z's internal pointers that are
followed. (The resulting string is of course a new item. The original
lists remain intact, pointed to variously as before.) The variables X and
Y are not involved. If you subsequently change the value of X so that it
no longer points to the list, this will not affect Z at all.
>
That use of 'get' (a variant of what I called 'deferring evaluation' in
>
previous
>
posts) is interesting when confronted to the ASLG:
>
>
The Get command [...] returns the value of an expression
>
[...] and assigns the value returned to the predefined
>
variable result.
>
>
[get] anyAppleScriptExpression
[...]
>
The word get in the Get command is optional because AS
>
automatically gets the value of expressions [...] when
>
they appear in scripts.
>
>
So, an OPTIONAL keyword makes the difference:
>
>
{"1", get item 1 of {3, 4}, 2000} as string
>
--> "132000"
>
{"1", item 1 of {3, 4}, 2000} as string
>
--> "1"
'Get' is only optional in 'get' commands. ;-) Seriously, though, the
items in the second list are all AppleScript objects (a string, a
reference, an integer) that are given as members of a list to be coerced.
AppleScript has no reason to suppose that any of them need to be
evaluated. The implied 'get' at the beginning of the line only gets the
result of the coercion, not the result of the list:
[get] {"1", item 1 of {3, 4}, 2000} as string
If you want a reference to be dereferenced, you have to use it in an
active context - such as the explicit 'get' in your first line, or the
'get' implied by a whole line of script:
[get] {"1", item 1 of {3, 4}, 2000}
[get] result as string
Or the 'get' implied by some operation:
{"1", [get] (item 1 of {3, 4}) as anything, 2000} as string
{"1", [get] (item 1 of {3, 4}) * 1, 2000} as string
Or to put it another way: If you write "MY TROUSERS" on a piece of slate,
put the slate on a piece of paper, and write to the left of it "Set fire
to ", your assistant will come in in the morning, read the instruction
"Set fire to MY TROUSERS", and coerce the garment to ash. If instead you
put the slate in a box - along with yesterday's Daily Telegraph a
three-toed sloth - and leave the message "Set fire to this box", the
slate will not turn to ash and neither will your trousers.
NG
----------
Geoff Garvey, 26th March 1915 - 29th August 2000
RIP, Dad. Lotsa love, Nig.