Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
In the 10.5 API almost all int or unsigned int parameters and return values are changed to NSInteger and NSUInteger. The NSInteger and NSUInteger types are defined to be the same size as pointers. I'm close to having this change complete and ready to commit for the GNUstep-base library, and wouldn't be worried about it but for the fact that it breaks compatibility on 64bit processors (though 32bit systems should be unaffected), since most 64bit processsors use 32bit integers and 64bit pointers, so the change means that most integers passed in the API will be twice as big on 64bit systems. Obviously that breaks binary compatibility on 64bit systesm, but perhaps less obviously it also breaks source code compatibility in quite a few places (wherever the API changes from passing a pointer to a 32bit integer to now be passing a pointer to a 64bit integer), and will cause compiler warnings wherever we assign a 64bit integer to a 32bit one. Possibly there will also be issues with archived data (including gorm files). So, how should we go about this? Do we update GNUstep-base, accepting that parts of the gui and back libraries (and applications and data) will be broken by the change, then fix breakage as we find it, or do we attempt to do some sort of coordinated change? If the latter, what would we try to coordinate, how would we manage it, and how would we test it? ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Allowing Applications to continue after exception...
On 8 Feb 2009, at 11:42, David Chisnall wrote: On 8 Feb 2009, at 06:47, Richard Frith-Macdonald wrote: Actually, I take it back ... maybe we can recover from an uncaught exception. Problem is ... if we are using native exceptions ... by the time the uncaught handler is called we have unwound the stack entirely and the program has no way to continue running. But maybe the native handling code can actually cope with that (or be changed to do that). I've been doing personality function hacking recently, so I'd be happy to take a look at this if it's desired. When the stack is unwound by native ('zero-cost') exceptions, the unwind library calls the personality function twice for each frame. The first time is to find the landing pad, the second time is to perform the unwinding (call cleanup code in each intervening frame and then continue unwinding). For a while, I've been pondering adding the Étoilé resumable exception stuff to the unwinding system. This would call the unhandled exception function at the top of the stack, before unwinding, and allow it to either call _Unwind_Resume() or continue, depending on the exception. It sounds like a good thing to have the option of resuming, even though it's generally not advisable. Do you have a patch for gcc/libobjc which would allow that? ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
Am Sonntag, den 22.02.2009, 09:55 + schrieb Richard Frith-Macdonald: > Obviously that breaks binary compatibility on 64bit systesm, but > perhaps less obviously it also breaks source code compatibility in > quite a few places (wherever the API changes from passing a pointer to > a 32bit integer to now be passing a pointer to a 64bit integer), and > will cause compiler warnings wherever we assign a 64bit integer to a > 32bit one. And those warnings should be taken seriously in any heterogeneous environment and the source code adapted accordingly. > Possibly there will also be issues with archived data (including gorm > files). IIRC, the actual size of the archived data is encoded into the archive and so if we heeded that information when decoding rather than the expected target size, we should be fine decoding the old values. But it seems that we are currently very strict in what we expect. And we have a bug... NSInteger is typedef'ed to gsaddr (which is typed def to gsuaddr) instead of gssaddr! So we are actually currently encoding unsigned integers when encoding NSInteger. > So, how should we go about this? Do we update GNUstep-base, accepting > that parts of the gui and back libraries (and applications and data) > will be broken by the change, then fix breakage as we find it, or do > we attempt to do some sort of coordinated change? I think we need to fix the NSInteger define. I think we should believe the archive/stream which were are decoding and convert into the expected type. We could warn if they types don't match but I don't think we should abort unless the types are so incompatible that we cannot sensibly convert. > If the latter, what would we try to coordinate, how would we manage > it, and how would we test it? I've attached a small test case that should test NSInteger... But I think for the test we want, we should create/commit architecture specific files in the test suite which should always decode to expected values on any platform. Cheers, David ArchivingUInteger.tar.gz Description: application/compressed-tar ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
Richard Frith-Macdonald wrote: > In the 10.5 API almost all int or unsigned int parameters and return > values are changed to NSInteger and NSUInteger. > The NSInteger and NSUInteger types are defined to be the same size as > pointers. > > I'm close to having this change complete and ready to commit for the > GNUstep-base library, and wouldn't be worried about it but for the fact > that it breaks compatibility on 64bit processors (though 32bit systems > should be unaffected), since most 64bit processsors use 32bit integers > and 64bit pointers, so the change means that most integers passed in the > API will be twice as big on 64bit systems. > > Obviously that breaks binary compatibility on 64bit systesm, but perhaps > less obviously it also breaks source code compatibility in quite a few > places (wherever the API changes from passing a pointer to a 32bit > integer to now be passing a pointer to a 64bit integer), and will cause > compiler warnings wherever we assign a 64bit integer to a 32bit one. > > Possibly there will also be issues with archived data (including gorm > files). > > So, how should we go about this? Do we update GNUstep-base, accepting > that parts of the gui and back libraries (and applications and data) > will be broken by the change, then fix breakage as we find it, or do we > attempt to do some sort of coordinated change? > If the latter, what would we try to coordinate, how would we manage it, > and how would we test it? > I would say that we should go on with this change. At some point we will have to do it to stay Cocoa compatible, so better do it now. On the other hand we need to make sure that we catch most of the problems as early as possible. Could those developers with 64-bit environments (I still don't use one) compile gui, back (all backends!) and as much applications as possible and report or fix all the compiler warnings they get. At the moment it is possible to compile gui and back with only limited compiler warnings, so most of the resulting warnings should be caused by the change. What we also need to do is change gui to use the new types. That is a lot more effort, I think it is even bigger than changing base. As far as Gorm file are concerned I would expect that they will stay the same. The on disk format must be compatible between 32- and 64-bit, so I don't expect any changes here. We may have to replace all calls to encodeInt with encodeInt32 and the same for decode, though. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Allowing Applications to continue after exception...
On 22 Feb 2009, at 10:24, Richard Frith-Macdonald wrote: On 8 Feb 2009, at 11:42, David Chisnall wrote: On 8 Feb 2009, at 06:47, Richard Frith-Macdonald wrote: Actually, I take it back ... maybe we can recover from an uncaught exception. Problem is ... if we are using native exceptions ... by the time the uncaught handler is called we have unwound the stack entirely and the program has no way to continue running. But maybe the native handling code can actually cope with that (or be changed to do that). I've been doing personality function hacking recently, so I'd be happy to take a look at this if it's desired. When the stack is unwound by native ('zero-cost') exceptions, the unwind library calls the personality function twice for each frame. The first time is to find the landing pad, the second time is to perform the unwinding (call cleanup code in each intervening frame and then continue unwinding). For a while, I've been pondering adding the Étoilé resumable exception stuff to the unwinding system. This would call the unhandled exception function at the top of the stack, before unwinding, and allow it to either call _Unwind_Resume() or continue, depending on the exception. It sounds like a good thing to have the option of resuming, even though it's generally not advisable. Do you have a patch for gcc/libobjc which would allow that? It won't require patching gcc, just libobjc. I don't have a patch currently, but I can probably create one fairly easily. It just requires adding an optional trampoline in the throw function that will bounce the exception out before unwinding the stack. The current code in Étoilé allows exceptions to be either resumed or restarted. Restarting jumps back to the start of the exception- handling block and lets the code try again. This is currently done in a really messy way. Ideally I'd want to make sure that the compiler inserts an entry into the DWARF table pointing to the start of this block and then let the unwind library walk back up the stack to find it. This is a much bigger change, and one I won't have time to do for a little while. David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
On 22 Feb 2009, at 09:55, Richard Frith-Macdonald wrote: Obviously that breaks binary compatibility on 64bit systesm, but perhaps less obviously it also breaks source code compatibility in quite a few places (wherever the API changes from passing a pointer to a 32bit integer to now be passing a pointer to a 64bit integer), and will cause compiler warnings wherever we assign a 64bit integer to a 32bit one. Can we defer this problem by defaulting to #defining NSInteger as intptr_t and NSUInteger as uintptr_t, but provide a GS_LEGACY_64 mode that compiles them as int and unsigned int and emits a warning? That way new code can use NSInteger and NSUInteger on 64-bit platforms in either mode, as long as all packages are compiled with the same options. Then, once all existing code has been modified to use the new types turn the flag off and break the ABI once? I suspect the bigger problem will be the CGFloat type, which is now used all over Cocoa. I really don't understand the reason for this change. It's float on 32-bit and 64-bit on 64-bit platforms, which almost sounds sensible until you remember that 32-bit and 64-bit floats are both computed using the 80-bit x87 unit on 32-bit x86 and so are the same speed, but are computed with the SSE unit on x86-64 and so calculations on doubles are often slower than the equivalent calculations on floats. If anything, the opposite definitions would make more sense for the architectures that Apple supports (especially since most GPUs still can't handle doubles sensibly, and a lot of the geometry calculations that use these types will probably end up being offloaded to the GPU in future versions). David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
On 22 Feb 2009, at 12:09, David Ayers wrote: Am Sonntag, den 22.02.2009, 09:55 + schrieb Richard Frith- Macdonald: Obviously that breaks binary compatibility on 64bit systesm, but perhaps less obviously it also breaks source code compatibility in quite a few places (wherever the API changes from passing a pointer to a 32bit integer to now be passing a pointer to a 64bit integer), and will cause compiler warnings wherever we assign a 64bit integer to a 32bit one. And those warnings should be taken seriously in any heterogeneous environment and the source code adapted accordingly. Yes... though in practice most will be harmless (but you have to check anyway). Possibly there will also be issues with archived data (including gorm files). IIRC, the actual size of the archived data is encoded into the archive and so if we heeded that information when decoding rather than the expected target size, we should be fine decoding the old values. Yes, but I'm not sure that this is true absolutely everywhere ... we need to check. But it seems that we are currently very strict in what we expect. And we have a bug... NSInteger is typedef'ed to gsaddr (which is typed def to gsuaddr) instead of gssaddr! Not in my (as yet uncommitted) code. So we are actually currently encoding unsigned integers when encoding NSInteger. Not really an issue ... since my changes to move everything over to NSInteger and NSUInteger haven't been committed yet, and when they are the commit will also include my fix to the typedef along with various other related fixes. So, how should we go about this? Do we update GNUstep-base, accepting that parts of the gui and back libraries (and applications and data) will be broken by the change, then fix breakage as we find it, or do we attempt to do some sort of coordinated change? I think we need to fix the NSInteger define. I think we should believe the archive/stream which were are decoding and convert into the expected type. We could warn if they types don't match but I don't think we should abort unless the types are so incompatible that we cannot sensibly convert. Really archiving/encoding/decoding should not be an issue ... except for errors in conversion where perhaps we encode an NSInteger and decode with a pointer to the wrong type: eg. int val; [coder decodeValueOfObjCType: @encode(NSInteger) at: &val]; Which could decode an 8 byte value into a variable which is only 4 bytes long. That sort of coding error is easy to make when converting a lot of code from using one type to another ... eg 'val' is actually an ivar declared in a separate header file, and you think you changed it from int to NSInteger, but forgot. We really need to check the code for any places where we pass pointers. If the latter, what would we try to coordinate, how would we manage it, and how would we test it? I've attached a small test case that should test NSInteger... But I think for the test we want, we should create/commit architecture specific files in the test suite which should always decode to expected values on any platform. Thanks .. I think we already have such tests for basic types. What we don't have is an exhaustive set of coding tests for every coding capable class. It would be good to add more. There are a few odd cases in the API where pointers are used. For instance, you can get the indexes from an NSIndexSet into a buffer. Now, if your code makes the buffer big enough for 10 unsigned int indexes (40 bytes) and retrieves them, but the base library is changed to use NSUInteger and copies 10 indexes (80 bytes) into the buffer, you have a problem. Those are the sort of issues I'm most concerned about, as I *hope* that our archiving/coding is architecture independent anyway (NSArchiver and NSUnarchiver and all coding using them certainly was architecture independent at one point). ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Allowing Applications to continue after exception...
On 22 Feb 2009, at 12:42, David Chisnall wrote: It sounds like a good thing to have the option of resuming, even though it's generally not advisable. Do you have a patch for gcc/libobjc which would allow that? It won't require patching gcc, just libobjc. I don't have a patch currently, but I can probably create one fairly easily. It just requires adding an optional trampoline in the throw function that will bounce the exception out before unwinding the stack. Yes please ... I'd love to try that out. The current code in Étoilé allows exceptions to be either resumed or restarted. Restarting jumps back to the start of the exception- handling block and lets the code try again. This is currently done in a really messy way. Ideally I'd want to make sure that the compiler inserts an entry into the DWARF table pointing to the start of this block and then let the unwind library walk back up the stack to find it. This is a much bigger change, and one I won't have time to do for a little while. I'm not sure about that ... it's certainly not needed by GNUstep and, while I can see the appeal, I can't think of any systems that actually allow re-execution of the 'try' block, so this would not fit into normal coding paradigms. What I'm really concerned about at the moment is trying to get code into the gcc distribution before the next release which would let me properly implement the Openstep/MacOS-X exception handling API when using objc native exceptions. It looks like that's just a function to set an uncaught exception handler. ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
On 22 Feb 2009, at 12:50, David Chisnall wrote: On 22 Feb 2009, at 09:55, Richard Frith-Macdonald wrote: Obviously that breaks binary compatibility on 64bit systesm, but perhaps less obviously it also breaks source code compatibility in quite a few places (wherever the API changes from passing a pointer to a 32bit integer to now be passing a pointer to a 64bit integer), and will cause compiler warnings wherever we assign a 64bit integer to a 32bit one. Can we defer this problem by defaulting to #defining NSInteger as intptr_t and NSUInteger as uintptr_t, but provide a GS_LEGACY_64 mode that compiles them as int and unsigned int and emits a warning? That way new code can use NSInteger and NSUInteger on 64- bit platforms in either mode, as long as all packages are compiled with the same options. Then, once all existing code has been modified to use the new types turn the flag off and break the ABI once? Yes we could ... my only reservation about doing that is, it's likely to end up with only one or two people actually using the new version ... so testing would be incomplete, and when we changed to the new mode we would discover a whole lot of breakage anyway, thus negating the point of doing it. It really depends on how many people are willing to commit to testing the change on 64bit systems. I suspect the bigger problem will be the CGFloat type, which is now used all over Cocoa. I really don't understand the reason for this change. It's float on 32-bit and 64-bit on 64-bit platforms, which almost sounds sensible until you remember that 32-bit and 64-bit floats are both computed using the 80-bit x87 unit on 32-bit x86 and so are the same speed, but are computed with the SSE unit on x86-64 and so calculations on doubles are often slower than the equivalent calculations on floats. If anything, the opposite definitions would make more sense for the architectures that Apple supports (especially since most GPUs still can't handle doubles sensibly, and a lot of the geometry calculations that use these types will probably end up being offloaded to the GPU in future versions). Interesting, I didn't realise that CGFloat actually resulted in poorer performance on 64bit systems. I guess we have to go ahead and change to match Apple anyway though :-( ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
Am Sonntag, den 22.02.2009, 12:50 + schrieb Richard Frith-Macdonald: > > But it seems that we are currently very strict in what we expect. And > > we have a bug... NSInteger is typedef'ed to gsaddr (which is typed def > > to gsuaddr) instead of gssaddr! > > Not in my (as yet uncommitted) code. Are you referring to the typedef or also about the strictness of decoding? Because currently anything encoded with NSInteger before your changes will not be decoded to the "new" NSInteger unless the sanity checks are removed. > > So we are actually currently encoding unsigned integers when encoding > > NSInteger. > > Not really an issue ... since my changes to move everything over to > NSInteger and NSUInteger haven't been committed yet, and when they are > the commit will also include my fix to the typedef along with various > other related fixes. Well yes... for any newly created archive... but what's with the archives that currently already contain NSInteger... the are currently encoded with 'I' and our decoding will expect 'i' after you commit. > >> So, how should we go about this? Do we update GNUstep-base, > >> accepting > >> that parts of the gui and back libraries (and applications and data) > >> will be broken by the change, then fix breakage as we find it, or do > >> we attempt to do some sort of coordinated change? > > > > I think we need to fix the NSInteger define. I think we should > > believe > > the archive/stream which were are decoding and convert into the > > expected > > type. We could warn if they types don't match but I don't think we > > should abort unless the types are so incompatible that we cannot > > sensibly convert. > > Really archiving/encoding/decoding should not be an issue ... except > for errors in conversion where perhaps we encode an NSInteger and > decode with a pointer to the wrong type: > eg. > int val; > [coder decodeValueOfObjCType: @encode(NSInteger) at: &val]; > Which could decode an 8 byte value into a variable which is only 4 > bytes long. > > That sort of coding error is easy to make when converting a lot of > code from using one type to another ... eg 'val' is actually an ivar > declared in a separate header file, and you think you changed it from > int to NSInteger, but forgot. > > We really need to check the code for any places where we pass pointers. I understand that you are worried about a different issue. But please be aware that changing the NSInteger typedef will also make archives containing them unloadable. > >> If the latter, what would we try to coordinate, how would we manage > >> it, and how would we test it? > > > > I've attached a small test case that should test NSInteger... But I > > think for the test we want, we should create/commit architecture > > specific files in the test suite which should always decode to > > expected > > values on any platform. > > Thanks .. I think we already have such tests for basic types. What we > don't have is an exhaustive set of coding tests for every coding > capable class. > It would be good to add more. This case is special in that it intentionally encodes as "int" and decodes as NSInteger (and encodes as "unsigned int" and decodes as "NSUInteger") and vice versa. [Well if you chose the "correct" #if] Now it may not be a big issue at all since we hardly @encode(NSInteger). The only instance I found is NSPointerArray which I believe has never been released. > There are a few odd cases in the API where pointers are used. For > instance, you can get the indexes from an NSIndexSet into a buffer. > Now, if your code makes the buffer big enough for 10 unsigned int > indexes (40 bytes) and retrieves them, but the base library is changed > to use NSUInteger and copies 10 indexes (80 bytes) into the buffer, > you have a problem. Indeed we also need to worry about this class of issues. > Those are the sort of issues I'm most concerned about, as I *hope* > that our archiving/coding is architecture independent anyway > (NSArchiver and NSUnarchiver and all coding using them certainly was > architecture independent at one point). Well.. this is not arch dependent (well with the exception that on some archs 'int' may be unsigned but I don't think we support them anyway). But I get an exception with the test case encoding as int and decoding as NSInteger, which implies to me that we are pretty strict in what we expect during decoding. Cheers, David ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: Compatibility breakage involved in upgrading to the MacOS-X 10.5 API
On Feb 22, 2009, at 13:50, David Chisnall wrote: I suspect the bigger problem will be the CGFloat type, which is now used all over Cocoa. I really don't understand the reason for this change. It's float on 32-bit and 64-bit on 64-bit platforms, which almost sounds sensible until you remember that 32-bit and 64-bit floats are both computed using the 80-bit x87 unit on 32-bit x86 and so are the same speed, but are computed with the SSE unit on x86-64 and so calculations on doubles are often slower than the equivalent calculations on floats. If anything, the opposite definitions would make more sense for the architectures that Apple supports (especially since most GPUs still can't handle doubles sensibly, and a lot of the geometry calculations that use these types will probably end up being offloaded to the GPU in future versions). Actually, the default for OS X programs is to use SSE in 32-bit builds as well. Changing to 64-bit types is bad for performance in general, not just for floating-point values. Increased flexibility is generally felt to be worth it. I suspect the relevant people felt it would be short- sighted not to take advantage of this ABI change to switch to doubles just because of minor limitations of current hardware; after all, the 128-bit transition won't happen for another four or five decades, while double-capable GPUs could easily be widespread in four or five years. -- Jens Ayton ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
NSView patch
this just makes debugging a bit easier if you guys want it... bug #25658 appears to be a bug in the NSView display stuff, because some random subset of a views subviews which don't need display are getting drawRect: called multiple times through _handleAutodisplay even though they needs_display = NO; with overlapping subviews this causes views which are below other views to be drawn above views which are above them. and its kind of a pain to debug when this flag is being set all over the place. matt foo.diff Description: Binary data ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSView patch
On Sun, Feb 22, 2009 at 8:29 AM, Matt Rice wrote: > this just makes debugging a bit easier if you guys want it... > > bug #25658 appears to be a bug in the NSView display stuff, > because some random subset of a views subviews which don't need display > are getting drawRect: called multiple times through _handleAutodisplay > even though they needs_display = NO; > with overlapping subviews this causes views which are below other > views to be drawn above views which are above them. > and its kind of a pain to debug when this flag is being set all over the > place. and here is a fix for the bug i was tracking down note that tests/Testing.h has a an EQ() macro that makes a different type of comparison but I didn't exactly understand what it was doing... there may be other things in NSGeometry requiring fixing, i haven't looked. bar.diff Description: Binary data ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev
Re: NSView patch
On 22 Feb 2009, at 21:31, Matt Rice wrote: On Sun, Feb 22, 2009 at 8:29 AM, Matt Rice wrote: this just makes debugging a bit easier if you guys want it... bug #25658 appears to be a bug in the NSView display stuff, because some random subset of a views subviews which don't need display are getting drawRect: called multiple times through _handleAutodisplay even though they needs_display = NO; with overlapping subviews this causes views which are below other views to be drawn above views which are above them. and its kind of a pain to debug when this flag is being set all over the place. and here is a fix for the bug i was tracking down Please can you explain how this fixes the bug (what the actual bug is). The reason I ask is that, though the idea of making NSEqualRects() consider slightly different rects to be equal seems fairly reasonable, it does not seem to be how it's implemented on MacOS-X. I found this by writing some tests to determine, by trial and error, the largest difference between two constants that was still considered equal in NSEqualPoints(), NSEqualSizes() and NSEqualRects() on MacOS- X, then changed the code on GNUstep to make it easy to set a breakpoint and examine the actual float values used. When I did that I found that the point where values began to be considered equal was the point where the compiler made the two constants into identical floats. ie. MacOS-X seems to be doing the same as our existing implementation and testing for exact float equality. If making NSEqualRects() fuzzy about its test for equality fixes your problem, perhaps the issue is in the way the function is being used somewhere? note that tests/Testing.h has a an EQ() macro that makes a different type of comparison but I didn't exactly understand what it was doing... It's testing to see if two values differ by an amount proportional to them rather than by an absolute amount. This is generally what is wanted if you need to test floats for equality and avoid test failures due to rounding errors. I have some more efficient code to do the same thing ... BOOL almostEqual(float A, float B) { #define threshold 10 // Arbitrary fuzziness of test union {int32_t i; float f;} valA, valB; valA.f = A; valB.f = B; /* * Make the values lexicographically ordered as twos-complement * integers. */ if (valA.i < 0) { valA.i = 0x8000 - valA.i; } if (valB.i < 0) { valB.i = 0x8000 - valB.i; } if (abs(valA.i - valB.i) < threshold) { return YES; } return NO; } ___ Gnustep-dev mailing list Gnustep-dev@gnu.org http://lists.gnu.org/mailman/listinfo/gnustep-dev