You’re right, that’s because va_list() is not supported in ASOC, it’s part of C’s stdarg.h.
Edit: To explain myself further: va_list() works only with C types (Object = Struct type) and ASOC doesn’t. %f is an floating point (double) but the given argument, created by AppleScriptObjC, is an object (read: C struct).
As what Nigel described match what I get with an other script ( and of course an other library ) I tried to run a slightly modified version of the script to see which is the striking error.
use theLib : script "NSNumbers"
set myVar to "0999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999"
repeat with i from 1 to 100000
try
set myVar to (theLib's incrementString:myVar)
on error errMsg number errNbr
return "" & i & " -| " & errMsg & " | " & errNbr
end try
end repeat
After compiling, I ran it and got :
“29767 -| Une erreur de type -4960 est survenue. | -4960”
I typed some returns at the end of the script, compiled and ran :
“29532 -| Une erreur de type -4960 est survenue. | -4960”
Each time I run the script with no change I get :
I am not even dangerous with ASOC, but I wonder if you could use NSValue to “unbox” ints, floats and the like with?
By unboxing, I mean, as an opposite as boxing, where you promote a scalar value to an object, to demote a value contained in an object into a value with scalar type.
And I am not saying that this necessarily produces any better solution than Shane already has come up with, just that I wonder if that can’t be used, to “bridge” between ASOC, and the more c- value typed methods and functions of Cocoa.
You’ll find the different codes for the types to use as an argument to the valueWithBytes method of NSValue, (so that you can bypass the @encode compiler directive in the Objective-C runtime reference in the section that deals with @encode (just google: objc @encode).
My excuse for not doing this testing myself is that this is not in my alley.
Edit+
Maybe this can’t be done after all, since you have to pass along a pointer with NSValue’s getValue method.
Maybe this can be done with: “a reference to fakedInt” or not, but when someone actually has, or if somebody already tested that, then we know for sure.
Edit++
IMHO: Apple should include a class named NSScalar for those occations, slightly misleading in its name as it should also be able to return rects, points, and sizes structs. (There is of course nothing that hinders anybody else in providing that class, that should aggregate upon NSValue, and return a pointer to memory, that is purged in the dealloc.) Such a class with methods for each datatype to return, would be really nifty to use from ASOC, because it would serve as a general interface to the c-part, and let you do other stuff than writing “wrapper-classes” the various places you need access to the c-parts. Shame such a scheme won’t work with function pointers.
Edit+++
You can of course use NSNumber’s intValue, unsignedLongLongValue and so on for the regular cases, but that was the problem in the first place, the unability of the ScriptingBridge to use anything less than an NSNumber. So, maybe wrapper classes, is the only way to interface with the c typed part of the interfaces after all.
Here is the stripped script allowing to test the behavior of a call to a library.
It’s extracted from a script driving Pages 5.1 which doesn’t allow us to extract easily the document’s contents so, GUIScripting is required.
Would be fine if you may test it from Apple’s Script Editor.
Don’t forget to save and install the library “Extractor Lib.scptd”
#=========
# extractor Lib
#=========
# ASObjC_Runner@yahoogroups.com 2014/03/06
# Shane STANLEY
use AppleScript version "2.3.1"
use scripting additions
use framework "Foundation"
on findPattern:thePattern inString:theString
set theRegEx to current application's NSRegularExpression's ¬
regularExpressionWithPattern:thePattern ¬
options:0 |error|:(missing value)
set theFinds to theRegEx's matchesInString:theString options:0 range:{location:0, |length|:length of theString}
set theFinds to theFinds as list -- so we can loop through
set theResult to {} -- we will add to this
set theNSString to current application's NSString's stringWithString:theString
repeat with i from 1 to count of items of theFinds
set theRange to (item i of theFinds)'s range()
set end of theResult to (theNSString's substringWithRange:theRange) as string
end repeat
return theResult
end findPattern:inString:
on makeUnique:theList
set theSet to current application's NSOrderedSet's orderedSetWithArray:theList
return theSet's allObjects() as list
end makeUnique:
#=====
As written before, AT FIRST RUN issue an error but behaves well after
→ error “Une erreur de type -4960 est survenue.” number -4960 from “extractor Lib”
Thanks in advance for your feedback.
Yvan KOENIG (VALLAURIS, France) mercredi 12 mars 2014 21:34:55
I think that the doubleValue keeps up with 37 decimal digits since the size of its storage is 8 bytes on a 64-bit processor, and it should hold for values less than 1.797693e+308, so that is really no problem to implement with NSDecimalNumber.
Of course this will not work when converting back to an AppleScript real, because of the loss of significant digits as statet above. I think the most you can convert is 12 decimal digits.
I realized that at the end of some post above, (the long one with many edits), that unless NSValue is somewhat excempted from the way the ObjC bridge deals with NSNumbers, Only uses an NSNumber internally, then it fails.
So I believe as you wrote in some posts above that you can only values back via an NSValue wrapper, not inject scalar values into an Objective-C method.
You can pass scalar values to a method as an argument – substringToIndex: is a perfect example. But it relies on the scripting bridge knowing about the requirements of the particular method, via a .scriptingbridge file in the relevant framework. In other words, it has to be defined in the method signature, and therefore set at framework compile time. That rules out format string tokens.
Well, it is a pity then, that you can’t use it, because especially the methods that takes format strings, can save some programming. I think, that adding an NSScalar class for ASOC’s explicit use, would be a much better design-wise approach, then to add the missing parts for explicit methods in the .scriptingbridge file!
I’ll finish off this by saying, that there isn’t much localization to be had with a digitstring, and it can’t indeed be localized anyway, as long as there are zeroes involved.
Of course the correct way to deal with currencies,dates and what-not that is localizable, is to use some subclass of NSFormatter.
For padding a number with leading zeros NSNumberFormatter is more appropriate than stringWithFormat, because.
¢ it’s the designated (and optimized) class to deal with number objects
¢ it can be easily used also in AppleScriptObjC
¢ precision is adjustable
¢ number format is adjustable
¢ localization is adjustable
I agree to the AppleScriptObjC, there isn’t much adjusting needed for numberformat, or localization, in this particular case with a string consisting of pure digits. What would have been a really good argument, would have been localization, but a string consisting of only digits are not localizable in the first place, the second you have to pad the string with zeroes.
As for stringWithFormat: I can adjust the length and precision (number of digits), and also choose among padding or no padding, (although I can’t pass in the padding as a parameter runtime, but I can pass a format string), and I don’t have to pad manually, which I guess makes it faster. At least it is fewer lines to write!
Only if the definition of saving programming is creating a script library or a framework to save up a few lines of code in AppleScript and the programming of the library or framework itself is not taken into consideration.
Ok, it seems to me like stringWithFormat, doesn’t manage as long strings of digits as 38 digits, so in those cases you are better off with using a numberFormatter. (I consider that a bug in stringWithFormat.)
The ease of use of a Framework, is of course important, but then again that ease of use lies in careful planning of the interfaces, and wasn’t really an issue at least I had in mind when we started this thread.
My goal was to save speed, say if you created a sequence of 1000+ numbers in one go. Now I have really learned that some place along the road to 38 digits, the stringwith format will lack precision. They probably refused to spend energy into upgrading this for 64 bits.