AppleScript Editor "could not be saved"

Hello

I tested a given proposal :

I used Find/Replace to convert

local FirstCharCantBeDigit, CCAllowedChars, CS6AllowedChars

set FirstCharCantBeDigit to {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}
set CCAllowedChars to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "€", "∞", "¢", "≠", "˜", """, "Ï€", "ø", " ", "∑", "Å“", "∂", "Æ’", "-", "Ë™", "∆", "Ëš", "-", ".", "-", "÷", "≥", "≤", "-", "-", "∫", "√", "-", "≈", "Ω", "â„¢", "¹", "º", "fi", "fl", "¡", "'", """, "∏", "°", "ž", "Å’", "", "˘", "Ëœ", "ˆ", "ı", "â—Š", "Ÿ", "ü"}
set CS6AllowedChars to {"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}

into


local FirstCharCantBeDigit, CCAllowedChars, CS6AllowedChars

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

In fact I did the trick on your complete script (plus one trio added to check that it can’t be saved).
The edited version saved flawlessly.
I applied Copy paste so that the set something trio was embedded twice the time it is in your origional script and this time it saves again flawlessly.
With 244 copies of the trio it saves again flawlessly.

It seems that with that we are on the good track.

KOENIG Yvan (VALLAURIS, France) samedi 28 septembre 2013 10:26:08

Hi Yvan.

Those elements should of course be ‘characters of .’ unless AppleScript’s text item delimiters are explicity set to “” or to {“”} first. They shouldn’t be assumed to be at their default setting.

Hello Nigel

Of course you are right. I made the changes too quickly.

KOENIG Yvan (VALLAURIS, France) samedi 28 septembre 2013 11:03:34

One other point: whether the error is triggered or not when saving manually can depend on whether you’re saving as run-only – for run-only scripts the threshold is a bit higher, because without the source there are fewer objects to be saved.

So in theory you could probably copy your script into a .applescript script, where autosaving is not a problem because it will only autosave as text, compile there, and export run-only, with more chance of success.

But I really wouldn’t advise that except in desperate circumstances…

A potential time-waster here is that we’re discussing a demo script which happens to contain several iterations of three list-setting lines. We’ve no idea what’s in the script which actually needs the cure.

However, we seem to be agreed from previous experience that the probable cause of the problem is data bloat and that Dan should be looking at ways to reduce the amount of data which AppleScript (at run time) and AppleScript Editor (during editing) try to store in the script file. The amount of data flying around while the script’s actually running shouldn’t be a problem as long as it’s not being held in persistent variables when the script exits.

Strategies (mostly suggested above) include:

¢ Don’t compile bulky objects as literal values into the script, but use less bulky alternatives, commands, and references to set them up when the script runs.
¢ Alternatively, store them somewhere other than in the script.
¢ Prefer local variables where possible so that their contents aren’t automatically saved to the script file when the script exits.
¢ Replace bulky values with minimal-bulk ones in persistent variables which don’t need to persist ditto.
¢ Don’t replicate data which could be shared or reused.

Hello Nigel

When I use properties, I define them with empty values.
I set their values when entering the script and reset the empty values when leaving the script.

property FirstCharCantBeDigit : {}
property CCAllowedChars : {}
property 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 {}

In fact I replicated 1 090 times the trio building the lists and was able to save the compiled script which reached 945 653 bytes. Of course it saved too after running because the properties were cleared on exit.
With an extraneous trio I was unable to save.

It seems that I reached the size limit for a compiled script.
Isn’t it a sufficient size ?

KOENIG Yvan (VALLAURIS, France) samedi 28 septembre 2013 18:23:19

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.