Am 20.08.2012 um 11:42 schrieb Ivan Vučica: On Mon, Aug 20, 2012 at 10:06 AM, David Chisnall <theraven@sucs.org> wrote:
It sounds like you're spending a lot of effort working around obscure corner cases that almost certainly will never appear in the wild.
It wasn't a lot of time, actually, at least until this problem cropped up :-)
CGPoint and NSPoint are supposed to be identical and code is allowed to cast between them and, more importantly, lots of existing code casts between arrays of NSPoint and arrays of CGPoint.
That's great, but despite it being the same, I still haven't seen this guarantee in the docs. In fact, existence of NSPointFromCGPoint() and NSPointToCGPoint() means it shouldn't be relied upon.
It appears that it was planned to make them exactly the same:
"We intend to fold these two types into one. However, this has not happened for Public Beta."
The original document cited isn't available any more.
And:
Special ConsiderationsPrior to Mac OS X v10.5 the coordinates were represented by float values rather than CGFloat values. When building for 64 bit systems, or building 32 bit like 64 bit, NSPoint is typedef’d to CGPoint .
I.e. since 10.8 you can expect NSPoint and CGPoint to be typedef'd...
But I have no idea how @encode() treats typedefs :)
I do concur that because casting between these types is widespread, this isn't much of a big deal. But, should we in the future go down the path of treating separate structs as the same type just because they have the same in-memory layout? Why would @encode even include the type name, then? Why would NSValue provide access to objCType? Am I forbidden from comparing these and making an informed decision on how to treat a data type based on that? What if NSSize was supposed to be animated or treated differently from NSPoint - should I lose the information that something was a NSSize just because it has the same in-memory layout?
I'd love to work around this, but since I'm dealing with KVC and KVO, I can't easily skip using NSValues to store structs and implement something of my own.
Plus, it worked correctly, and now it's broken. :-)
C structs are just blobs of memory. If they are structurally equivalent then, for all practical purposes, they are interchangeable.
In any case, there's still a bug, even if the original issue is about to be dismissed. (I still consider that if I put one thing into the NSValue, I should be getting the same thing out - even if the memory layout is the same. Otherwise, let's also patch @encode in clang and gcc.)
If 'from' contains a NSValue with a 'NSPoint' in it (or something that claims to be an NSPoint created through from = [NSValue valueWithBytes: &fromPt objCType: @encode(CGPoint)];
the following still doesn't work and sets only the .x member: CGPoint fromPt = { 0 }; [from getValue:&fromPt]; I'm sure it's a problem with getValue: since removing initialization of fromPt means I end up with junk in .y.
For this to work correctly, the getValue method must deduce the struct size from the objCType (provided at time of NSValue creation). If it does not correctly, it is a bug.
AFAIK, NSValue is not expected to be able to convert between types. But it should provide whatever was stored.
So, the problems: I have a NSValue with a CGPoint in there, I can't tell it's a CGPoint, and fetching it results in a failure. :-)
A final though: NSValue was not designed with CG* in mind. So you can't expect it to behave in any way. Apple has the same problem and is doing behind-the-scenes decisions to optimize their code (see citations above). Thse may look more and more illogical to the original design of NSValue and may need more and more special case handlers.
Nikolaus
|