I only posted the one script. The second script came from @ccstone. While I can't speak for him, I think the easiest way to account for the differences between my script and his is simply to say that we have different scripting styles. I don't see one as being better or worse than the other here.
I declare the variable _M
by reference so that it doesn't get evaluated at the time of its declaration. When you declare by reference, it allows you do perform tests and actions on it that "de-reference" and evaluates the contents of the variable when you are ready to do so.
Why does that matter here ? If I were to declare _M
by value, and give it the object reference menu items of menus...of my process whose name starts with...
, if any of those children in the hierarchy don't exist, the script will terminate with an error. That's also one reason I chose to declare the individual children in their plural form, instead of ...of menu 1 of...menu bar item "Bookmarks" of menu bar 1...
, because the collective object reference (e.g. menus
) will always return a value, even if it's an empty list, whereas menu 1
either exists or it doesn't, the latter being error-creating.
So, in fact, when the script goes on to check the existence of _M
, it's really only confirming that the process "Safari"
is running, and that the entire collection contains at least one physical object in its collection, and isn't just an empty list, {}
, or nested sets of empty lists, e.g. {{{}, {}}, {}, {}, {{}, {}}}
.
If I had used specific children in their singular forms, (e.g. menu 1
, menu bar item "Bookmarks"
, etc., which is completely fine to do, and arguably more sensible in some ways), then checking for its existence and getting a true
result would confirm to you that every one of those children definitively exists.
Yes, you wouldn't be the first to remark on my unusual coding style.
The first part of the line is testing for existence, as I described above. The second part is less transparent. This:
set [M] to _M
is basically shorthand for:
set M to item 1 of _M
WHY? Because of how AppleScript allows you to co-assign variables by assigning lists of values to lists of variables:
set [a, b, c] to [1, 2, 3]
Here, a
, b
, and c
are assigned the respective values of 1
, 2
, and 3
. If you try and do a similar expression where there are an excess of variables and not enough values to fill them, AppleScript throws an error:
set [a, b, c] to [1, 2] --> error "Can’t get item 3 of {1, 2}." number -1728
But... if you have an excess of values and not enough variables, then AppleScript fills the variables in order with the respective values until it runs out of variables. Then the remaining, unused values are discarded:
set [a, b] to [1, 2, 3]
Here, a
= 1
, b
= 2
, and 3
is lost to the wind. So, hopefully, you can see why set [M] to _M
is equivalent to set M to item 1 of _M
.
What's less obvious is how on earth it picked out item 1
to be the object that appears to materialise deep inside a set of nested lists, surrounded above, below, left and right by a load of empties...
That's the other reason to declare _M
by reference. Since the variable hasn't been evaluated before accessing its items, i.e. is still in a fully referenced state, it only typically needs to evaluate a collection as minimally deep as necessary to obtain the requested objects, and it ignores values that don't exist (which later materialise in the form of an empty list when the variable is dereferenced).
Once the variable is dereferenced, then you lose these features as they evaluate to physical AppleScript objects in a list of lists, where empty values are replaced with empty lists (a physical data object). This would also be true had I declared _M
by value.
You can demonstrate the effect of dereferencing on the way list items are accessed by comparing the current return value for M
with the one that gets returned if we do this instead:
if _M exists then set [M] to (_M as list)
_M as list
is a coercion that forces the variable to evaluate and makes a nested list of hell. Then when we try and access the first element, all you get back is another nested list of hell that is one level shallower than before. It turns out that, in this case, the location of the menu item we're after inside the dereferenced list is given by:
set M to item 1 of item 1 of item 7 of item 1 of (_M as list)
I hope this helps bring some clarity to things. Feel free to ask if have any more queries.