How Do I get the Default App?

Shane et al: I just wanted to mention that this script does not seem to need
use framework "AppKit"

It seem to run just fine without it.

All is not as it seems :slight_smile:

The NSWorkspace class is part of AppKit, so you should include the appropriate use framework statement. That doesn’t mean it won’t run without it — the framework’s info is probably already cached. But as a matter of reliability you should always include use statements for any frameworks you, well, use.

(Foundation and AppKit are going to be loaded by any host anyway, but the use statement is also key to AppleScript loading the framework’s .bridgesupport file, and without that some scripts simply won’t work. Better safe than sorry.)

Or perhaps more simply:

set appName to nsAppName's stringByDeletingPathExtension() as text
1 Like

Shane, thanks for the clarification.

Is there any overhead, or penalty, for including a use framework statement that is not needed?

UPDATE: 2017-11-27 01:11 GMT-0600

FYI, I have tested the script without the use framework "AppKit" in these apps, and it runs find in all:

  • SD6
  • Script Editor
  • Script Geek
  • FastScripts
  • Keyboard Maestro

None that I’ve been able to measure.

(The proper “test” would be to quit the apps first, which I’m assuming you did.) In fact, this script doesn’t use anything that requires loading the .bridgesupport file, so it’s likely to be fine regardless. But that’s not exactly obvious to most scripters. And you leave yourself open to having problems if you edit it later.

And perhaps just as important for Script Debugger users, the presence or otherwise of a use framework statement is used to determine what terminology is offered in code-completion. So if you leave out AppKit, you won’t be offered NSWorkspace or any of its methods. And using code completion is not only a labor-saver (I shouldn’t have to tout the benefits of automation around here!), but it also offers a lot of hints to getting the code right.

In that case I have no reason to not always include it in my standard script setup. It will now be:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework “AppKit”
use scripting additions

Any objections?

The only real drawback is that it adds a lot of terminology to code-completion (as in more than doubling the amount). But otherwise it’s probably no worse than including use scripting additions just in case.

I was categorically told (off) by Apple Engineering about this: don’t include any use statements that are not required in the script at hand.

And I was chided for including use scripting additions rather than wrapping use with using terms from :roll_eyes:

In the real world, I reckon there are worse things to worry about — and particularly leaving them out when they should be included.

I just spent the last 20 minutes trying to find the correspondence (to no avail) as I can’t remember the exact reasons why they said this (I remember the tone, though…let’s say the bedside manner leaves a bit to be desired).

As best as my buggy CerebralOS can remember, it was along the lines of not introducing unnecessary dependencies, possible name clashes, unknown bugs. i.e., nothing specific, just general good coding practice.

It’s certainly best practice. But I think some allowance needs to be made for the target user base. For example, NSAttributedString is in Foundation, but it also has methods in AppKit.

I guess the issue here is that someone — and this isn’t the first time or place I’ve seen this — has suggested they can leave use statements out because it worked for them. If the alternative is to err the other way, that seems to me to be likely to be less troublesome in the long run.

Oh, and I was also chided for using PDFKit instead of Quartz. Maybe we can just use Cocoa :wink:

(For lurkers, I’m only joking about using Cocoa.)

That’s a bit rough! ASLG’s coverage of use scripting additions says: “If a script uses use scripting additions, AppleScript may optimize scripting addition commands, sending them to the current application instead of the current target (it) when it does not change the meaning to do so. […] Without a use scripting additions command, AppleScript must use a less efficient dispatching scheme, so explicitly declaring them is recommended.” — while at the end of using terms from it says: "using terms from scripting additions does not enable optimization of scripting addition commands as use scripting additions does."

Hmm, I don’t want get into an argument about it, but no, that wasn’t the tenor of the reply I got from Apple. It was more the contrary: include use framework statements only when they’re needed; if you don’t need them, you’ve no business putting them in.

This (to my mind) is the same advice as not importing a framework you don’t need into a Cocoa app, or not importing unnecessary modules into a python script.

FWIW, I think it’s good advice; I just didn’t happen to like the way it was delivered.

But it’s not as bad as it sounds, because the optimisation is only required in code targeting an application, and such code won’t generally compile inside a using terms from scripting additions block anyway.

One of the differences, though, is framework stuff is cached. If you launch with the environment variable ASDebugLibraryLoads set, you’ll see when you run a script with a use framework statement, it’s loaded the first time, and from then on it’s only referenced (speaking on a per-app basis).

I agree with you in principle. I just think it’s a minor issue in the scheme of things.

Thanks to all for this excellent discussion about use statements.

To Shane’s point, I think it makes a difference whether you are writing code for a client to use in a production environment, or in writing code for yourself (and maybe a few friends/colleagues) to use in your/their personal Mac.

It also depends on the type of scripts you will be writing. I’m at the point where many, if not most, of my scripts will directly, or via handlers/script libraries, use ASObjC.

So, since Shane has told us:

I feel comfortable in using a standard set of use statements, not knowing for sure if I will need all of them or not. So, I think I will stick with my default setup:

use AppleScript version "2.5" -- El Capitan (10.11) or later
use framework "Foundation"  -- this may not be required
use framework "AppKit"  -- this may be not be required
use scripting additions

## Some Scripts may work with Yosemite, but no guarantees ##
#  This script has been tested ONLY in macOS 10.11.6+

If at some point in the future I find that including one of these that isn’t required causes a problem, then I will adjust accordingly.

FWIW, you will always need Foundation.

Even if I am not using any ASObjC?

Sorry for the confusion — only when using ASObjC.

1 Like

Hey Folks,

@CJK came up with this on the Keyboard Maestro Forum a while back.

Life got in the way, and I forgot about it until rediscovering it just now.

-Chris

--------------------------------------------------------
# Auth: CJK from Keyboard Maestro Forum
#     : Modified by Christopher Stone <scriptmeister@thestoneforge.com>
# dCre: 2019/04/24 20:03
# dMod: 2019/04/24 20:03 
# Appl: AppleScriptObjC
# Task: Find the Default Handler Application for a Given URL-Protocol.
# Libs: None
# Osax: None
# Tags: @CJK, @Applescript, @Script, @ASObjC, @Find, @Handler, @Internet, @Protocol, @Web
# URLs: https://forum.keyboardmaestro.com/t/activate-main-browser-which-are-different-on-systems-where-i-use-the-same-set-of-synced-macros/13572/4
--------------------------------------------------------
use framework "Foundation"
--------------------------------------------------------
property currentApp : a reference to current application
property NSWorkspace : a reference to NSWorkspace of currentApp
property NSURL : a reference to NSURL of currentApp
--------------------------------------------------------

set urlType to NSURL's URLWithString:"http:"

set appPath to (NSWorkspace's sharedWorkspace()'s URLForApplicationToOpenURL:urlType) as text

# activate the application named appPath

--------------------------------------------------------