3

It appears that AppleScript knows the special value null.

How do I return such a value from my Cocoa Scripting based app for a scriptable property?

If I return nil (NULL) or NSNull for a scriptable property getter from my Cocoa Scripting-based app, the script editor interprets that as missing value.

And if I return [NSAppleEventDescriptor nullDescriptor], AppleScript even shows an error.

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149

2 Answers2

1

AppleScript uses a typeNull descriptor to indicate unassigned/no value, whereas missing value is represented by a typeType descriptor of cMissingValue. (It's analogous to the undefined vs null mess in JavaScript, and a similar PITA.)

foo
  • 3,171
  • 17
  • 18
  • Are you saying that it should be possible for me to return a null value from my app code? How, then? – Thomas Tempelmann Apr 29 '16 at 16:32
  • The point is: don't. AppleScript doesn't handle 'undefined' well, and frankly like JS's `undefined` it's a misfeature that should never have been introduced at all. Use 'missing value', which is analogous to JS's `null`; that's what it's there for. `typeNull` descriptors should only be used as the root in an object specifier chain. (While AEM defines dedicated `typeObjectBeingExamined` and `typeCurrentContainer` types to indicate the roots of relative references, an absolute reference, i.e. one relative to the app's root 'application' object, just uses `typeNull` to indicate that root.) – foo Apr 29 '16 at 22:02
  • AS knows both a "missing value" and a "null" value, and they're distinct, you realize that? When I ask about returning a null value, I meant the AppleScript "null" value. That's what I want to return. You seem to assume I want to return a "missing value", which is not what want. – Thomas Tempelmann May 02 '16 at 07:33
  • 1
    There is a `null` keyword defined in the depths of AppleScript's aeut, along with other busted or useless crap; don't use that. And don't be thinking about scripting languages as if they were C; they're not: they don't have pointers, so they don't have C-style null pointers either. Use the standard `missing value` object to indicate an "omitted" value (c.f. JS's `null` object, Python's `None` object, Ruby's `nil` object, etc), or define your own enumeration/value-class if your app needs a `null` keyword that has a specific meaning to itself (e.g. if your app is some sort of programmer tool). – foo May 02 '16 at 09:34
  • If you want more specific advice, you'll need to tell us more about the app itself: what it does and what the class/property terminology you're defining is meant to represent. – foo May 02 '16 at 09:35
  • 1
    This question is related to the linked one about using records. I wanted to be able to let the user check if a record value is non-existing, and the "whose" clause does not appear to work with exists, so I thought returning a special value, such as null, would help with that. I understand I could use yet another value that I define myself, but that seems wrong to me if I could just use the already existing "null" from AS. – Thomas Tempelmann May 02 '16 at 10:26
  • 1
    Regarding that other post, use `missing value` to indicate an "empty" property. The Cocoa Scripting framework will (mostly) automatically bridge between `nil` and `missing value` for you. And a `whose` clause should be able to filter on your elements' `owner` property, e.g. `tell application "Contacts" to every person whose organization = missing value`. I suggest you post relevant portions of your sdef and code there, and/or make up simple test cases to narrow it down; while CS is not short of its own bugs and shortcomings, you should make sure it's not something in your implementation first. – foo May 02 '16 at 10:50
  • @foo do you have any thoughts about the code in the answer I just posted? Why is "current application" being substituted in? Which "nil" value should I be using? – pkamb Sep 27 '18 at 23:41
1

I'm using the cMissingValue version of "null", like so:

NSAppleEventDescriptor(typeCode: UInt32(cMissingValue))

I decided to use that based on the testing below.

I'm using Swift to run and passing parameters to an AppleScript subroutine, using the code here:

Passing variables to an AppleScript

let parameters = NSAppleEventDescriptor.list()

let null         = NSAppleEventDescriptor.null()
let missingValue = NSAppleEventDescriptor(typeCode: UInt32(cMissingValue))

parameters.insert(null, at: 0)
parameters.insert(missingValue, at: 0)
return parameters

These parameters are passed to the AppleScript subroutine, and I've commented each results:

on nilTest(paramNull, paramMissingValue)
    display dialog paramNull buttons {"OK"} # execution error: Can’t make current application into type string. (-1700)
    display dialog paramMissingValue buttons {"OK"} #"msng"

    display dialog "" & paramNull buttons {"OK"} #"current application"
    display dialog "" & paramMissingValue buttons {"OK"} #"missing value"
end nilTest

The NSAppleEventDescriptor.null() version seems to for some reason be getting the "current application" value.

It seems like I may want to use the cMissingValue as shown in the other answer.

The variables can be nil-checked in AppleScript like so:

if yourVar is missing value then
    display dialog "is missing value" buttons {"OK"}
end if

NSAppleEventDescriptor.null() does not hit this check. Type cMissingValue does.

I've added it as a Swift Extension: NSAppleEventDescriptor.missingValue()

extension NSAppleEventDescriptor {

    static func missingValue() -> NSAppleEventDescriptor {
        return NSAppleEventDescriptor(typeCode: UInt32(cMissingValue))
    }

}
pkamb
  • 33,281
  • 23
  • 160
  • 191