views:

18

answers:

1

I am confused by AppleScript references... I almost never develop in AppleScript, and am having a very difficult time finding good documentation on how AppleScript handles references. The following code fails because AppleScript Can’t make firstValue of hash into type reference.:

on run
    foo()
end run

on foo()
    set the hash to {firstValue:1, secondValue:2}
    set the hashRef to a reference to the hash
    return the firstValue of hashRef
end foo

But the following code works -- same code, but I am running it inside the run handler instead of the foo handler:

on run
    set the hash to {firstValue:1, secondValue:2}
    set the hashRef to a reference to the hash
    return the firstValue of hashRef
end run

Why does the first code example fail while the second code example works? Better question, can someone point me in the direction of documentation explaining this so I can learn what my mistake is?

EDIT: Philip's answer pointed me in the right direction and I now see what confused me. The official AppleScript docs state that "AppleScript passes all parameters by reference, which means that a passed variable is shared between the handler and the caller, as if the handler had created a variable using the set command". However, this does not mean that AppleScript is passing an AppleScript Reference Object as each parameter!

Here's the following, more detailed, code example, to show the final working solution I developed:

on run
    foo()
end run

on isRef(someValue)
    try
        someValue as reference
        return true
    on error
        return false
    end try
end isRef

on foo()
    log "In foo()"
    set the objectList to makeObjectList()
    log "objectList isRef =" & isRef(objectList)
    set theObject to makeObject given id:0, name:"Test"
    addObjectToObjectList(theObject, objectList)
    log "foo(): object name =" & name of theObject
    log item 1 of allItems of objectList
    log item 1 of goodItems of objectList
    set the name of item 1 of allItems of objectList to "Test3"
    log item 1 of allItems of objectList
    log item 1 of goodItems of objectList
end foo

on makeObjectList()
    set the hash to {allItems:{}, goodItems:{}, badItems:{}}
    return the hash
end makeObjectList

on makeObject given name:theName, id:theId
    set theObject to {name:theName, id:theId}
    return theObject
end makeObject

on addObjectToObjectList(object, objectList)
    log "In addObjectToObjectList"
    log "object isRef =" & isRef(object)
    copy object to the end of allItems of the objectList
    set objectRef to a reference to the last item in allItems of the objectList

    set name of objectRef to "Test2"
    log "object name =" & name of object


    log "objectRef isRef =" & isRef(objectRef)
    log "objectRef name =" & name of (contents of objectRef)
    copy objectRef to the end of goodItems of the objectList
end addObjectToObjectList

The output of that is as follows:

(*In foo()*)
(*objectList isRef =false*)
(*In addObjectToObjectList*)
(*object isRef =false*)
(*object name =Test*)
(*objectRef isRef =true*)
(*objectRef name =Test2*)
(*foo(): object name =Test*)
(*name:Test2, id:0*)
(*name:Test2, id:0*)
(*name:Test3, id:0*)
(*name:Test3, id:0*)

The point being, I can't make references to local variables within a handler -- but I can make references to parts of a record as long as those references are stored back into that Record, which is the functionality I was after.

I doubt anyone will ever read this far down into this question :-)

A: 

I really think it's an issue of scope here. If I declare a reference to a selection in both the Finder and InDesign from within foo() getting a reference and values contained within works. But since you're not working within a specific app, the target has to be in the scope of the script. Knowing Applescript—and its legendary wonkiness—that could be the "correct" way of using the reference operator.

I was able to make this work if I made the hash a global property of the script, like the following: property hash : {firstValue:1, secondValue:2}. I was then able to call the value successfully from foo(). Full example code:

property hash : {firstValue:1, secondValue:2}

on run
    foo()
end run

on foo()
    set the hashRef to a reference to the hash
    return the firstValue of hashRef
end foo

Not a specific answer to the question, but one that will get you through your day.

Philip Regan
Thanks @Philip! As I continue to debug my script I am now running into a much more complex reference issue but you deserve the accept for this one. If I can't figure out my more complex issue, I'll post a new question.
Josh
@Philip: I see now what confused me. I'm going to edit my answer and post some additional details, but apparently what confused me was that "AppleScript passes all parameters *by reference*", but this does **not** mean the same thing as "AppleScript passes references for all parameters". In other words, there's two kinds of references in AppleScript!
Josh
@Philip: If you'd like your brain to hurt, read my edited question. I think I'm quitting for the day now, HA!
Josh
I think you just added a couple creases into my brain. I'm glad I was able to help. Cheers
Philip Regan