AppleScript Editor "could not be saved"

Hello.

Now if you have anything that relates to that amount of data in a real script, so that it won’t compile, then you can either split your script into several scripts, and call that script, if the state that it is made for occurs, or read in data from a file as necessary, for instance paragraph 3 or something, which would then contain the characters, or whatever, for that given circumstance.

Hello.

Try running the script below, close it, and then open it and rerun it while you watch the log window.
You will see that local variables are not stored between runs at the root level of a script.

local a
try
	log a
on error
	log "a is undefined"
end try
set a to 5

Hello.

It’s sort of confusing this, a variable, either declared at the top level of a script, or in a script’s run handler is a global variable, in the sence that it’s value will be stored like a property.
Now, this isn’t exactly the same as a global variable, as a global variable is visible to scripts that you load after you have declared the variable global. But a variable declared global, is also stored like a property!

So a variable declared global, is more kind of an universal variable, than just a global. :slight_smile:

Hello kel

In your sample, a is not declared as local. In fact, it is a global as every variable defined in the main script.

Try to run this one twice.


property i : 0
local a
if i = 0 then
	set i to 1
	set a to {1, 2, 3}
end if
a

This time, a is defined as local.
At first run it’s set to {1,2,3} and, at second run the local is undefined and you will got the logical error message :
error “La variable a n’est pas définie.” number -2753 from “a”

There is a sufficient number of oddities in AppleScript, there is no need to invent ones.

KOENIG Yvan (VALLAURIS, France) dimanche 29 septembre 2013 09:35:35

Hi Yvan.

In a situation where a global scope is needed but values don’t need to persist between runs of the script, I’d personally use globals instead of properties. It makes little difference to what actually happens, but the intention’s clearer:

global FirstCharCantBeDigit, CCAllowedChars, CS6AllowedChars

set FirstCharCantBeDigit to characters of "0123456789"
set CCAllowedChars to characters of "abcdefghijklmnopqrstuvwxyz0123456789€∞¢â‰ ˜"πø ∑œ∂ƒ-˙∆˚-.-÷≥≤--∫√-≈Ω™¹ºï¬ï¬‚¡'"∏°žÅ’˘˜ˆı◊Ÿü"
set CS6AllowedChars to characters of "abcdefghijklmnopqrstuvwxyz0123456789"

set FirstCharCantBeDigit to {}
set CCAllowedChars to {}
set CS6AllowedChars to {}

WIth regard to globals, I’m a fan of the fact that if they’re declared only in the handlers where they’re used, instead of at the top of the script, their “globality” only applies in those handlers and the ‘run’ handler:

log aHandler() -- aHandler sets the value of a global declared in it.
log bHandler() -- bHandler knows about it because it's declared there too.
log FirstCharCantBeDigit -- The run handler knows about globals anyway.
log cHandler() -- cHandler doesn't know about it because the it's not declared there.

on aHandler()
	global FirstCharCantBeDigit
	
	set FirstCharCantBeDigit to "Hello"
	return FirstCharCantBeDigit
end aHandler

on bHandler()
	global FirstCharCantBeDigit
	
	return FirstCharCantBeDigit
end bHandler

on cHandler()
	return FirstCharCantBeDigit
end cHandler

The above is the same as declaring ‘FirstCharCantBeDigit’ global at the top of the script and explicitly declaring it local in ‘cHandler’.

Declaring a global in an explicit ‘run’ handler has the same effect as not declaring it there. It’s still a global, but its scope only only extends to other handlers where it’s been so declared.

In a sane world. Yes. :wink:

Hi kel.

The key word here is “normally”. See what I’ve just posted about globals above.

Hi.

That really means that a variable that isn’t declared globally in the run handler, still is a global, so whether you declare a variable global or not in the run handler makes no difference, since all variables declared in the run handler without a local scope is global per definition.

As for local variables, I think the AppleScript Language guide has an unfortunate wording in the section Kel mentions, as whence something is rest, has nothing to do if it is stored or not. It will of course always be reset when it is run, since it is never stored.

:slight_smile:

Edit

While we are talking about this subject, of storage, I find it worth mentioning, that sometimes it is feasible to avoid storing a new value in a global, due to some misheap or some other condition, then one avoids storage, by exiting the script with error number −128. In order to get values stored, you must also run it from a script runner that writes back properties. Some programs comes with their own script runners, and not all of those stores properties. Then you can save a script object from within your script with the properties, which you reload from within your main script the next time it runs.

Hello Nigel

(1) I never really understood the difference between global and property

(2) most of the time, I use properties when I wan’t to fasten the treatment of lists.
I always assumed that globals doesn’t behave the same for that.

KOENIG Yvan (VALLAURIS, France) dimanche 29 septembre 2013 12:33:19

Right. Run handler variables are global by default, but it’s as if they’ve been declared global within the run handler itself. They can only be seen elsewhere if also declared global at the top of the script (so they can be seen everywhere in the script) or in other handlers (so they can be seen in those handlers).

When using an implicit run handler, it’s not immediately clear that property and global declarations are “top of the script” and not part of the run handler.

Properties and globals (including run handler variables) are permanent features of the script and their values are saved back to the script file whenever the script’s run from that file. Local variables are only temporary and cease to exist when the scope in which they’re used exits.

They do, actually. Since they belong to the script, they can be “referenced” by writing ‘my’ in front of them (or ‘of me’ after them, of course).

It still strikes me as a bit of case of the tail wagging the dog. Using chmod a-w solves the problem, but doesn’t interfere with what you want to do otherwise.

True – but that has its downside, in that it’s something that can’t be tracked in one place, so in long scripts it can be a bit of a hunt to check where a global is declared.

Each to his/her own, I suppose. In scripts for running, I avoid using properties and globals at all where possible because it annoys the hell out of me to have the file’s modification date change every time. :wink:

Thanks for the chmod idea, although its effect has to be undone before the script can be opened in AppleScript Editor, so it’s not much help with the original problem here.

Hmmm. One might have to resort to a comment. :wink: Seriously, though, hunting applies to properties and globals generally in long scripts. If you’re reading a piece of code which suddenly accesses a variable it hasn’t set, you’ve got to ascertain whether the variable’s a global or a property or a mistake and then, if it’s either of the first two, go looking for the code which will have set it most recently. With a global declaration at the top of each relevant handler, at least you’re forewarned when you start reading and only have to check out handlers with the relevant declarations at the top.

The “where possible” can come in to play a fair bit, though.

To twist a slogan, there’s a script for that. :wink:

Fair, um, comment…

It’s generally preferable, but it’s also not always possible. You can’t do it if you have a combination of run, open and idle handlers, for example. Also, if the value is modified or set in a called handler, globals/properties can eliminate the need to deal with complex return values.

Hello. I agree with Shane, it is a phlethora of good reasons for using globals and properties.

Encapsulation outranks modularity (I am not going to discuss it), in my book, and script objects with properties, that serves as “class variables”, is the best solution I see, for sharing contents between handlers, and at the same time concealing it for the calling handler. You can also call a handler in that script object to initialize any data.
Now, introducing a global, may seem contradictory to encapsulation, but when it is used as a shared variable among handlers that serves a common purpose, that is exactly what it does. -It helps encapsulate stuff that the caller doesn’t need to know about.

Now this makes for a little bit more typing, than using globals, but it feels so much safer, than having globals around. I for instance have a hard, coming up with new variable names at all times, and I don’t declare the scope at all times, so sooner or later, I’ll either overwrite a global, or get overwritten by a global, a bug that will take some time to find.

On the other hand, you avoid typing if you use globals, and globals are also visible from other script that also has declared the same global, which is very nice.

All in all, I am very happy with the scoping rules, and how it all works in AppleScript. :slight_smile:

Say you have a handler that modifies one or more globals/properties. That means you not only have to pass the values in as arguments, but depending on their class you may also have to pass their values back as part of the handler’s return value. So a simple return value, or no return value, becomes a list of values. And it’s all adding to the complexity of the script.

It is a whole lot more complicated than that. First of all, how you construct a program, varies with the size of the final product, and your choice of language will also influence the style.

Encapsulation, is something that enforces modularity, but it is mainly for reducing visiblity → “information hiding”. That is something you will want to do, if you are writing script libraries, or large scripts. Unless it is a one off anyway.
But encapsulation, has great advantages, when it comes to maintainance of programs, as you can then relate to much smaller part off the program than you otherwise would, with variables sprinkled through the program, and it also reduces the number of parameters that needs to be remembered. And that is a real bonus, when AppleScript Obj C Explorer is the only editor around with code completion!

A BIG thanks to everyone that has posted that I now know the reason and the fix for this. :smiley:

I need to set about streamlining and possibly breaking up a few larger scripts we use but have already been able to make and save amendments to the one script which wouldn’t save previously.

Thanks again, I’m happy for this post to carry on as discussion into the merits of global variables and so on. :slight_smile:

To be clear: AppleScriptObjC Explorer is the only editor with AppleScriptObjC code-completion. Script Debugger has AppleScript code-completion.

Well, I better get around to testing it, when I say codecompletion, I mean code completion like in Xcode with Objective-C. :slight_smile: Autocompletion, being something entirely different.