On Dec 18, 2013, at 12:01 PM, Hengist Podd <email@hidden> wrote:
Ironically, the latest AppleScript release is no longer OSA-safe either since it caches loaded libraries at the per-Component Instance level rather than per-script; thus two unrelated AppleScripts loaded into in the same CI can similarly conflict if they happen to use the same libraries and those libraries contain settable properties.
The scope for script libraries is intentional and entirely in keeping with OSA. It allows libraries to have global state across multiple clients, such as a cache. It is an implementation detail of a given library as to whether it has any global state, and it’s entirely up to the library developer to determine whether it makes sense to have any. If there were no ability to have global state, then it would be impossible to write some libraries. Global state is a fundamental feature of libraries in practically every programming and scripting language.
Keep in mind that libraries can use other libraries and build upon one another, e.g., a library that reads XML files uses a file I/O library; therefore, a library can itself be a client of other libraries. Without the ability for multiple client scripts (some of which may themselves be libraries) to share the same library instance and its global state, it would be impossible in some cases for a client to fetch a value from library A, pass it into library B, then have B pass that value along to A to perform further operations on it. e.g., a client opens a file with the file I/O library and passes the opened-file value to an XML library to tell it to read from that file using the file I/O library. This is how dylibs/frameworks work, for example.
Libraries should not have publicly visible properties unless they’re meant to be shared among clients. Moreover, even if global state is stored in a property of a library object, libraries will usually provide handlers for performing operations that depend on this state; it should be exceedingly rare to have a library that has a property that clients are expected to set (and if one does, it’s because it’s a feature of that library that multiple clients will see the same value).
Libraries that provide per-client state should do so by providing a handler that returns a value for the client to interact with. e.g., a file I/O library could have a handler for constructing an object that represents a file that you can then send messages to open/read/write/close; alternatively, like the Standard Addition commands, the library could provide an open handler that returns an integer that represents the open file and can be given as an argument to read/write/close handlers, and so forth. The top-level library object you get when you reference a library is not meant to be a per-client value; rather, it should provide a means to create per-client state when asked.
Having said that, it’s not unthinkable that a library might be designed for the caller to make a copy of it in order to create per-client state. However, that’s probably only appropriate for very simple libraries, and makes it more difficult to change the library in the future (because the library doesn’t get sent a message that it can handle to modify the behavior of creating per-client state).
By the way, “per-client” really means per-caller. e.g., typically a file I/O library would return two different references to a file if a given client script asks to open it twice.
Coming at it from the other direction: restricting libraries to component instances instead of sharing them across all instances means that host programs can decide how and whether to sequester scripts into groups that share global state. This has always been the OSA model. Scripts inside the same component instance have always shared global state, e.g., all the properties of the AppleScript object, like "text item delimiters”, the set of user identifiers, and state that’s part of the component instance, like the sendProc and mode flags. When you run scripts inside Script Editor, it puts each script into its own component instance, since it’s a development environment and you don’t expect independent script documents to interact with one another just because they happen to be open at the same time. Even then, a script document that uses libraries that use libraries all see the same instance of each given library, because they’re all in the same component instance.
Hengist, have you brought up this issue for discussion before and I missed it? I would have been happy to explain how the new script libraries feature works had I known you had questions.
-- Chris Page
The other, other AppleScript Chris
|