I’m experiencing an odd bug (at least, I assume that’s what it is) with a program I’m writing, and it only appears to occur under Leopard, and not under Tiger .
The program has an outline view that gets its data from a data source; every time something changes (like when the user adds new data, or changes existing numbers in the outline view), a function adds stuff up to make sure everything is OK. At seemingly random intervals, though, one of two things happens: either one of the integers in the table gets set to -2147483648 (that is, the lowest value an integer can have), or I get a pop-up error window informing me that -4.294967284E+9 can’t be converted into type integer. This while there is nothing in the code I wrote that would set the variables involved to these values.
This doesn’t happen very predictably, either: if I do the exact same thing twice, it may occur one time and not the other, or both times, or not at all. All I can say is that if I keep at it for a while, I’ll get the mistake/error/bug/whatever.
Now, like I said it didn’t do this under Tiger, and when I tested the program under Tiger again the other day, I couldn’t reproduce the problem. This even though I was using the exact same version of the program as I used under Leopard a few minutes earlier, where it did show this behavior.
I have a feeling something goes wrong with the data source, but I have no idea how to go about checking if that is the problem, and if it is, how to solve it. Googling for it didn’t get me any solutions, or even make me think it’s a known problem, so any suggestions would be very welcome .
I knew I’ve seen those numbers before. Basically they come from the int (integer) data type in the c language… and thus objective-c too… and thus probably applescript too. C variables have sizes and these errors indicate that the value of your variable is exceeding the limit of the int data type. I can’t explain how or why but take a look at this web page that talks about the int data type… maybe it will give you a clue. It’s at the bottom of the page.
Yep, I had already thought of that, too ” that’s why I mentioned “the lowest value an integer can have” The problem with this theory is that the values of the variables involved shouldn’t get anywhere near those numbers. The function where the problem seems to occur, adds up a small number of 0’s, 1’s, 2’s etc. to a maximum total value of maybe 10 or 15. Because of the small number of actual values being added up, it shouldn’t ever get anywhere even remotely near 2^31, and since no negative numbers are involved at all, it also should not be able to go below 0.
There’s a link to the program’s web site in the first post, which includes the source code as it was at that point .
As background information, this is for a program to ease the paperwork for the tabletop wargame AT-43 when creating units of soldiers before playing a game.
The outline view contains entries for units, with “underneath” each unit the options it has been given; the function below goes through the options and adds them up for each unit, then updates the unit line to show the right numbers (so if you add an officer to a unit, for example, it will make the unit line reflect that there is now one more officer than there was before). This is easier to see if you download the program and try it, than it is for me to explain in a few words, I think.
The thing is that these options generally increase the values of the variables (numberOfOfficers, numberOfSpecialWeapons, etc.) by 1, 2 or 3, and there are usually only a few options per unit. There are no negative numbers involved in most fields, and like I said before, there aren’t enough things being added up to set variables to large values ” even double digits are rare.
By writing values to the log, I’ve determined that things seem to go wrong before it gets to the five “set contents of data cell” lines after the “end repeat”, BTW.
on addUpUnitStats()
set AP to 0
repeat with currentUnit in data items of data source of outline view "Company" of scroll view "Company" of view "Company" of split view "Vertical" of window "Main"
set totalOptionsAP to 0
set numberOfOfficers to 0
set numberOfSpecialWeapons to 0
set numberOfSpecialists to 0
set numbersBonus to 0
repeat with currentOption in data items of currentUnit
set optionAP to (contents of data cell "FixedAP" of currentOption) as integer
if contents of data cell "AppliesToAll" of currentOption is true then
set optionAP to optionAP + ((contents of data cell "APperFighter" of currentOption) as integer) * ((contents of data cell "Fighters" of currentUnit) as integer)
else
set optionAP to optionAP + ((contents of data cell "APperFighter" of currentOption) as integer) * (((contents of data cell "Officers" of currentOption) as integer) + ((contents of data cell "SpecialWeapons" of currentOption) as integer) + ((contents of data cell "Specialists" of currentOption) as integer))
end if
set numberOfOfficers to numberOfOfficers + ((contents of data cell "Officers" of currentOption) as integer)
set numberOfSpecialWeapons to numberOfSpecialWeapons + ((contents of data cell "SpecialWeapons" of currentOption) as integer)
set numberOfSpecialists to numberOfSpecialists + ((contents of data cell "Specialists" of currentOption) as integer)
set numbersBonus to numbersBonus + ((contents of data cell "NumbersBonus" of currentOption) as integer)
set contents of data cell "AP" of currentOption to optionAP
set totalOptionsAP to totalOptionsAP + optionAP
end repeat
set contents of data cell "Officers" of currentUnit to numberOfOfficers
set contents of data cell "SpecialWeapons" of currentUnit to numberOfSpecialWeapons
set contents of data cell "Specialists" of currentUnit to numberOfSpecialists
set contents of data cell "NumbersBonus" of currentUnit to numbersBonus
set contents of data cell "MaxFighters" of currentUnit to ((contents of data cell "MaxFighters" of currentUnit) as integer) + numbersBonus
checkUnit(currentUnit)
if contents of data cell "MaxedUnit" of currentUnit is true then
set unitAP to ((contents of data cell "MaxAP" of currentUnit) as integer) + totalOptionsAP
else
set unitAP to ((contents of data cell "BaseAP" of currentUnit) as integer) + (((contents of data cell "APperFighter" of currentUnit) as integer) * (((contents of data cell "Fighters" of currentUnit) as integer) - (contents of data cell "MinFighters" of currentUnit) as integer)) + totalOptionsAP
end if
set contents of data cell "AP" of currentUnit to unitAP
set AP to AP + unitAP
end repeat
set contents of text field "Current AP" of window "Main" to AP
checkAP()
end addUpUnitStats
if contents of data cell "AppliesToAll" of currentOption is true then
set optionAP to optionAP + ((contents of data cell "APperFighter" of currentOption) as integer) * ((contents of data cell "Fighters" of currentUnit) as integer)
else
Are you sure these numbers can’t be large? What about data cell “Fighters” ?
There are typically about 6 to 12 fighters in a unit, plus a few extras ” I’d be surprised to see a value higher than 15. In any case the error seems to occur much more often with the other fields, like data cell “Officers”, data cell “SpecialWeapons”, etc. The AP-related cells may have values in the hundreds (1,000 or so at most), but that’s it. Nothing that gets remotely close to 2^31.
Also, the error message has changed. After a suggestion by someone else to do an integer → string → integer conversion to see if the problem might be related to that somehow, it now reports that “” cannot be changed into type number ” even after I changed the code back to what it was before.
Good idea! Let me quickly try that . No difference, unfortunately
This makes me think that some other routine is corrupting the data, perhaps storing a number as text. I’m not sure how that would result in the errors you’re seeing though.
Thanks! It does seem to solve the problem, but causes others . like how to avoid empty fields without setting them to 0 (which throws off other parts of the program).
I’m ever more seriously considering re-writing the whole *&#(^(@^ing thing in Python, but that has the twin problems that I first need to figure out how PyObjC actually works (which might be relatively easy if all the tutorials and introductions I’ve found so far weren’t outdated .), and that once I’ve done that, it’s going to be a huge amount of work again
That’s pretty much what I figured ” but the question still remains why it doesn’t do that every time, and only under Leopard?