@property problem
-
So, I'm trying to be a good little Obj-C 2.0 programmer and use these
newfangled properties. Xcode doesn't seem to appreciate my attempts.
I've boiled the problem down to this snippet:
@interface MyWindow : NSWindow
{
}
@property(readwrite) BOOL capturing;
@end
@implementation MyWindow
@synthesize capturing;
@end
When I compile that, I get the error:
error: synthesized property 'capturing' must either be named the same
as a compatible ivar or must explicitly name an ivar
AFAICT, "capturing" IS the name of my ivar. What is it *really*
complaining about? What did I do wrong?
Thanks!
randy -
Properties don't allocate storage, they simply provide a mechanism for
accessing it.
You need to declare your ivar somewhere:
@interface MyWindow : NSWindow
{
id capturing;
}
+Melissa
On Feb 11, 2008, at 13:14, Randall Meadows wrote:
> So, I'm trying to be a good little Obj-C 2.0 programmer and use
> these newfangled properties. Xcode doesn't seem to appreciate my
> attempts.
>
> I've boiled the problem down to this snippet:
>
> @interface MyWindow : NSWindow
> {
> }
> @property(readwrite) BOOL capturing;
>
> @end
>
> @implementation MyWindow
>
> @synthesize capturing;
>
> @end
>
> When I compile that, I get the error:
>
> error: synthesized property 'capturing' must either be named the
> same as a compatible ivar or must explicitly name an ivar
>
> AFAICT, "capturing" IS the name of my ivar. What is it *really*
> complaining about? What did I do wrong?
>
>
> Thanks!
> randy
-
On 2/11/08, Randall Meadows <cocoa-dev...> wrote:
> AFAICT, "capturing" IS the name of my ivar. What is it *really*
> complaining about? What did I do wrong?
You are incorrect. Re-read the documentation closely; on 32-bit
architectures (the "non-fragile instance variable runtime") you must
provide an instance variable for your property. If it does not have
the same name as the property, you must specify this in your
declaration.
On 64-bit architectures, you can omit the ivar declaration.
Also, you have not specified a memory management method in your
@property declaration, which you must do if you are not using garbage
collection.
HTH,
--Kyle Sluder -
> I've boiled the problem down to this snippet:...
>
> @interface MyWindow : NSWindow
> {
> }
> @property(readwrite) BOOL capturing;
> error: synthesized property 'capturing' must either be named the
> same as a compatible ivar or must explicitly name an ivar
You haven't declared a compatible ivar named "capturing". You'd need
to do something like this:
@interface MyWindow : NSWindow
{
BOOL capturing; // <-- here!
}
@property(readwrite) BOOL capturing;
The line marked above declared an ivar with the same name and the same
type as your property declaration, so now synthesize will be able to
do its thing.
Obj-C *can* be smart enough to generate this ivar for you behind the
scenes, but only if you're using the 64bit runtime. If you don't
require 32bit compatibility, turn it off, and then you don't have to
worry about declaring these ivars for synthesize.
Cheers,
-Joshua Emmons -
On Feb 11, 2008 1:27 PM, Melissa J. Turner <mjturner...> wrote:
> Properties don't allocate storage, they simply provide a mechanism for
> accessing it.
They can allocate storage.
Review: <http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
es/chapter_5_section_8.html#//apple_ref/doc/uid/TP30001163-CH17-SW3>
-Shawn -
On Feb 11, 2008, at 1:27 PM, Melissa J. Turner wrote:
> You need to declare your ivar somewhere:
>
> @interface MyWindow : NSWindow
> {
> id capturing;
> }
...or in this particular case:
@interface MyWindow : NSWindow
{
BOOL capturing;
}
j o a r -
On Feb 11, 2008, at 16:28, Kyle Sluder wrote:
> Also, you have not specified a memory management method in your
> @property declaration, which you must do if you are not using garbage
> collection.
It defaults to "assign." Declaring that for a BOOL would be
(unnecessarily) redundant.
/brian -
A big THANKS to all of you who responded so quickly to point out my
absent-mindedness of not actually *declaring* my "capturing" ivar. I
can't tell you how many times I overlooked that simple fact when I was
comparing my code to the sample code in the ObjC 2.0 docs.
Please consider me sufficiently flogged for being a bonehead. (No
actual noodles were harmed.)
On Feb 11, 2008, at 2:14 PM, Randall Meadows wrote:
> So, I'm trying to be a good little Obj-C 2.0 programmer and use
> these newfangled properties. Xcode doesn't seem to appreciate my
> attempts.
>
> I've boiled the problem down to this snippet:
>
> @interface MyWindow : NSWindow
> {
> }
> @property(readwrite) BOOL capturing;
>
> @end
>
> @implementation MyWindow
>
> @synthesize capturing;
>
> @end
>
> When I compile that, I get the error:
>
> error: synthesized property 'capturing' must either be named the
> same as a compatible ivar or must explicitly name an ivar
>
> AFAICT, "capturing" IS the name of my ivar. What is it *really*
> complaining about? What did I do wrong?
-
FYI: The property name doesn't have to match the instance variable
name, so it's OK to keep using prefixes on your ivar names. So you
could declare the class as
@interface MyWindow : NSWindow {
BOOL _capturing; // or mCapturing or whatever
}
@property(readwrite) BOOL capturing;
@end
and then in the implementation use
@synthesize capturing=_capturing;
I strongly recommend prefixing all instance variables, to avoid
confusion with locals. I've also found out the hard way that it's even
more important to do this with properties.
Not prefixing property instance vars can lead to a type of mistake
where, in the implementation of the same class, you accidentally write
something like
contents = [NSArray array];
when you meant to write
self.contents = [NSArray array];
Do you see the problem? Assuming no GC, and the 'contents' property is
marked 'retain' or 'copy', the first line will cause a crash sometime
later on, because you directly assigned an autoreleased value to an
instance variable, so sometime after this method leaves scope, that
array is going to be dealloced and 'contents' will be a bad pointer.
The second line invokes the property's setter method, which correctly
retains or copies the array.
—Jens
PS: To forstall an FAQ: Yes, it is kosher to use "_" as your ivar
prefix, even though the Foundation and AppKit classes do the same.
Name collisions are not a problem. It is, however, recommended to not
use "_" as a method name prefix, because you can collide with and
accidentally override internal superclass methods. -
On 2/11/08, Brian Christensen <brian...> wrote:
> On Feb 11, 2008, at 16:28, Kyle Sluder wrote:
>
>> Also, you have not specified a memory management method in your
>> @property declaration, which you must do if you are not using garbage
>> collection.
>
> It defaults to "assign." Declaring that for a BOOL would be
> (unnecessarily) redundant.
Not true for non-GC code (which is what I specified). The compiler
will issue a warning if you do not explicitly declare a memory
management model, because "This encourages you think about what memory
management behavior you want and type it explicitly." (From
http://developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/Articl
es/chapter_5_section_3.html#//apple_ref/doc/uid/TP30001163-CH17-SW2
).
--Kyle Sluder -
On Feb 11, 2008, at 2:32 PM, Kyle Sluder wrote:
>>> Also, you have not specified a memory management method in your
>>> @property declaration, which you must do if you are not using
>>> garbage
>>> collection.
>>
>> It defaults to "assign." Declaring that for a BOOL would be
>> (unnecessarily) redundant.
>
> Not true for non-GC code (which is what I specified). The compiler
> will issue a warning if you do not explicitly declare a memory
> management model
It will only issue a warning for object properties, not for non-object
properties.
j o a r -
Is there any performance penalty for using the 64 bit runtime? In
general what are the disadvantages of disabling 32 bit compatibility
other than the obvious fact that my program wouldn't run on 32 bit
machines?
On Feb 11, 2008, at 4:29 PM, Joshua Emmons wrote:
> Obj-C *can* be smart enough to generate this ivar for you behind the
> scenes, but only if you're using the 64bit runtime. If you don't
> require 32bit compatibility, turn it off, and then you don't have to
> worry about declaring these ivars for synthesize.
-
On Feb 11, 2008, at 3:33 PM, Adam P Jenkins wrote:
> Is there any performance penalty for using the 64 bit runtime? In
> general what are the disadvantages of disabling 32 bit compatibility
> other than the obvious fact that my program wouldn't run on 32 bit
> machines?
If you are the first 64 bit app launched on the system, there will be
a slightly performance penalty as all of the 64 bit versions of the
various dylibs are mapped into memory.
Obviously, you can't deploy a 64 bit application to 32 bit only macs;
the performance is infinitely bad, in that case. :)
The performance characteristics of Objective-C changes slightly in 64
bit. Message dispatch and instance variable access changes
slightly. It is unlikely that this will change application
performance significantly.
The 64 bit ABI also features a unified ObjC/C++ exception model. It
is often called "zero cost". This is not really true; it simply
shifts the expense related to exception handling from the setup of the
handler to when an exception is actually thrown. It can have a huge
[positive] impact on your application's performance if you have lots
and lots of exception handlers but few exceptions are ever thrown.
Of course, your memory footprint will be slightly larger in that
everything that is pointer sized will be doubled in size. This is
both a direct and indirect impact in that some structures may have a
bit more padding to ensure correct alignment for pointers.
The Garbage Collector works just fine in 64 bits.
b.bum -
> Is there any performance penalty for using the 64 bit runtime? In
> general what are the disadvantages of disabling 32 bit compatibility
> other than the obvious fact that my program wouldn't run on 32 bit
> machines?
By default on Leopard only 32-bit apps run, so you only have the 32-
bit versions of libraries loaded. When the first 64-bit Cocoa app
runs, that's a lot of libraries that need to be loaded... I don't
know what the increase in memory usage is quantitatively, but afaik
it's non-trivial.
This has been discussed in detail on a mailing list before, at some
point, but I can't find it in the archives or via Google.. :/
Wade -
On 2/11/08, j o a r <joar...> wrote:
> It will only issue a warning for object properties, not for non-object
> properties.
Once again, devil, meet details.
--Kyle Sluder -
On Feb 11, 2008 AD, at 4:33 PM, Adam P Jenkins wrote:
> Is there any performance penalty for using the 64 bit runtime? In
> general what are the disadvantages of disabling 32 bit compatibility
> other than the obvious fact that my program wouldn't run on 32 bit
> machines?
The 32-bit frameworks and libraries are around a decade old; the 64-
bit frameworks and libraries are essentially at version 1.0 and are
nowhere near as mature. As a result, they have some interesting bugs
that don't exist in the 32-bit frameworks. I've filed them as I've
found them...
Nick Zitzmann
<http://www.chronosnet.com/> -
On Intel, 64-bit code supposedly runs somewhat faster, as it uses a
different instruction set with considerably more registers available.
(The regular x86 has only four registers, IIRC. Or maybe that was the
Z80.) On PowerPC, the G5 uses the same instruction set in 64-bit, so
it doesn't make a difference.
Of course, 64-bit code uses more memory for pointers, which increases
cache misses and paging, so whether it's actually faster probably
depends on exactly what the code does...
—Jens -
On 11 Feb 08, at 19:44, Jens Alfke wrote:
> On Intel, 64-bit code supposedly runs somewhat faster, as it uses a
> different instruction set with considerably more registers
> available. (The regular x86 has only four registers, IIRC. Or maybe
> that was the Z80.) On PowerPC, the G5 uses the same instruction set
> in 64-bit, so it doesn't make a difference.
32-bit x86 has eight registers: eax, ebx, ecx, edx, esi, edi, ebp, and
esp. (The last two are basically reserved, though.) x86-64 has sixteen
registers. -
On 2/11/08 2:11 PM, Jens Alfke said:
> PS: To forstall an FAQ: Yes, it is kosher to use "_" as your ivar
> prefix, even though the Foundation and AppKit classes do the same.
> Name collisions are not a problem.
Could you elaborate? If I subclass NSView and add an ivar named
"_sisterView" then in some future SDK NSView.h also gets a _sisterView
ivar, wouldn't there be a compiler error? If only Apple uses the
underscore prefix and I don't, then there will be no conflicts.
Pity private ivars have to be in public headers...
--
____________________________________________________________
Sean McBride, B. Eng <sean...>
Rogue Research www.rogue-research.com
Mac Software Developer Montréal, Québec, Canada -
On Feb 12, 2008, at 7:58 AM, Sean McBride wrote:
>> PS: To forstall an FAQ: Yes, it is kosher to use "_" as your ivar
>> prefix, even though the Foundation and AppKit classes do the same.
>> Name collisions are not a problem.
>
> Could you elaborate? If I subclass NSView and add an ivar named
> "_sisterView" then in some future SDK NSView.h also gets a _sisterView
> ivar, wouldn't there be a compiler error?
Yes, and that's why I believe Jens is telling you that it's OK to use
the same prefix for ivars as anyone else that you're sharing code
with: Because any name clashes would be immediately apparent. This in
contrast to, for example, method names.
> Pity private ivars have to be in public headers...
Agreed, that is truly a pity.
j o a r -
On 12 Feb '08, at 7:58 AM, Sean McBride wrote:
> Could you elaborate? If I subclass NSView and add an ivar named
> "_sisterView" then in some future SDK NSView.h also gets a _sisterView
> ivar, wouldn't there be a compiler error?
Yes, but not a runtime error, and it wouldn't break binary
compatibility. So it wouldn't affect users, only you (or other people
using your source code), and it's easy to fix with a quick Refactor
command.
Unlike a method-name conflict, which _would_ break existing binary
copies of your app, in strange and hard-to-predict ways.
—Jens -
> Yes, and that's why I believe Jens is telling you that it's OK to
> use the same prefix for ivars as anyone else that you're sharing
> code with: Because any name clashes would be immediately apparent.
> This in contrast to, for example, method names.
Note that this isn't true in the 64-bit runtime, where ivars don't
have to be declared publicly. There, AFAIK, ivars are uniqued by name
still, so unexpected clashes are possible (and wouldn't be detected at
compile time, necessarily... someone less lazy than me should write
some test cases and find out :) ).
Wade -
Okay, but why the diff? Why should it matter whether you're using 32
or 64 bits? Storage is still storage, and it seems you'd still need
to provide that storage even under a 64-bit runtime.
On Feb 11, 2008, at 3:29 PM, Joshua Emmons wrote:
>> I've boiled the problem down to this snippet:
>>
>> @interface MyWindow : NSWindow
>> {
>> }
>> @property(readwrite) BOOL capturing;
> ...
>> error: synthesized property 'capturing' must either be named the
>> same as a compatible ivar or must explicitly name an ivar
>
> You haven't declared a compatible ivar named "capturing". You'd
> need to do something like this:
>
> @interface MyWindow : NSWindow
> {
> BOOL capturing; // <-- here!
> }
> @property(readwrite) BOOL capturing;
>
> The line marked above declared an ivar with the same name and the
> same type as your property declaration, so now synthesize will be
> able to do its thing.
>
> Obj-C *can* be smart enough to generate this ivar for you behind
> the scenes, but only if you're using the 64bit runtime. If you
> don't require 32bit compatibility, turn it off, and then you don't
> have to worry about declaring these ivars for synthesize.
>
>
> Cheers,
> -Joshua Emmons
-
Because changing the 32 bits runtime to support this kind of feature
would have break binary compatibility with previous version, and
previous applications.
This is the same for "zero-cost" exceptions that works with 64 bits
applications, but not with 32 bits applications.
And it is also the case for the fragile ivar problem that was solve in
the 64 bits runtime.
Le 16 févr. 08 à 23:35, William Squires a écrit :
> Okay, but why the diff? Why should it matter whether you're using 32
> or 64 bits? Storage is still storage, and it seems you'd still need
> to provide that storage even under a 64-bit runtime.
>
> On Feb 11, 2008, at 3:29 PM, Joshua Emmons wrote:
>
>>> I've boiled the problem down to this snippet:
>>>
>>> @interface MyWindow : NSWindow
>>> {
>>> }
>>> @property(readwrite) BOOL capturing;
>> ...
>>> error: synthesized property 'capturing' must either be named the
>>> same as a compatible ivar or must explicitly name an ivar
>>
>> You haven't declared a compatible ivar named "capturing". You'd
>> need to do something like this:
>>
>> @interface MyWindow : NSWindow
>> {
>> BOOL capturing; // <-- here!
>> }
>> @property(readwrite) BOOL capturing;
>>
>> The line marked above declared an ivar with the same name and the
>> same type as your property declaration, so now synthesize will be
>> able to do its thing.
>>
>> Obj-C *can* be smart enough to generate this ivar for you behind
>> the scenes, but only if you're using the 64bit runtime. If you
>> don't require 32bit compatibility, turn it off, and then you don't
>> have to worry about declaring these ivars for synthesize.
>>
>>
>> Cheers,
>> -Joshua Emmons
>
-
But it doesn't answer the question. Why even make the change in
the 64-bit runtime? This would seem to hide a source of bugs, by
taking the responsibility for providing storage away from the
programmer. Some storage is still necessary. And besides, in order to
take advantage of Leopard features like this one (whether on PPC or
Intel), you should still have to link against the 10.5 SDK, so it
would seem more reasonable to make the update to both the 32 and 64-
bit runtimes, but only in the 10.5 SDK. Then you could update the
10.5 SDK (to 10.5.1) to allow for this "syntactic sugar" under both
32- and 64-bit.
I mean, after all, all it means is that you're changing the
default size of an (Integer) register in the CPU chip, and updating
the OS to take advantage. How would this make implementing (or not
implementing) this change any harder or easier?
On Feb 16, 2008, at 6:03 PM, Jean-Daniel Dupas wrote:
> Because changing the 32 bits runtime to support this kind of
> feature would have break binary compatibility with previous
> version, and previous applications.
> This is the same for "zero-cost" exceptions that works with 64 bits
> applications, but not with 32 bits applications.
> And it is also the case for the fragile ivar problem that was solve
> in the 64 bits runtime.
>
> Le 16 févr. 08 à 23:35, William Squires a écrit :
>
>> Okay, but why the diff? Why should it matter whether you're using
>> 32 or 64 bits? Storage is still storage, and it seems you'd still
>> need to provide that storage even under a 64-bit runtime.
>>
>> On Feb 11, 2008, at 3:29 PM, Joshua Emmons wrote:
>>
>>>> I've boiled the problem down to this snippet:
>>>>
>>>> @interface MyWindow : NSWindow
>>>> {
>>>> }
>>>> @property(readwrite) BOOL capturing;
>>> ...
>>>> error: synthesized property 'capturing' must either be named the
>>>> same as a compatible ivar or must explicitly name an ivar
>>>
>>> You haven't declared a compatible ivar named "capturing". You'd
>>> need to do something like this:
>>>
>>> @interface MyWindow : NSWindow
>>> {
>>> BOOL capturing; // <-- here!
>>> }
>>> @property(readwrite) BOOL capturing;
>>>
>>> The line marked above declared an ivar with the same name and the
>>> same type as your property declaration, so now synthesize will be
>>> able to do its thing.
>>>
>>> Obj-C *can* be smart enough to generate this ivar for you behind
>>> the scenes, but only if you're using the 64bit runtime. If you
>>> don't require 32bit compatibility, turn it off, and then you
>>> don't have to worry about declaring these ivars for synthesize.
>>>
>>>
>>> Cheers,
>>> -Joshua Emmons
>>
-
On Feb 17, 2008, at 10:59 AM, William Squires wrote:
> But it doesn't answer the question. Why even make the change in the
> 64-bit runtime? This would seem to hide a source of bugs, by taking
> the responsibility for providing storage away from the programmer.
> Some storage is still necessary. And besides, in order to take
> advantage of Leopard features like this one (whether on PPC or
> Intel), you should still have to link against the 10.5 SDK, so it
> would seem more reasonable to make the update to both the 32 and 64-
> bit runtimes, but only in the 10.5 SDK. Then you could update the
> 10.5 SDK (to 10.5.1) to allow for this "syntactic sugar" under both
> 32- and 64-bit.
> I mean, after all, all it means is that you're changing the default
> size of an (Integer) register in the CPU chip, and updating the OS
> to take advantage. How would this make implementing (or not
> implementing) this change any harder or easier?
One thing to remember is that if you were to do this, you would need
another entire copy of all the system frameworks - one for the 32 bit
"compatibility" version (for apps linked with 10.4) and another for
the new features that you'd get with linked-with-10.5 apps.
This may not seem like much (since disks are cheap, though we are
talking a lot of space - and going from 1 to 2 DVDs to install Leopard
would be a non-trivial impact) but all of these frameworks get loaded
into memory as well. For example, turn on activity monitor and look
at memory usage once you launch your first 64 bit app. See the nice
big jump in used memory? That's the 64 bit apps, and for now, there
aren't a lot of 64 bit apps out there to make this a problem (and they
tend to be targeted to markets that have lots of memory installed,
etc..).
If this sort of memory usage were to be hit when using "common level"
apps, the whole user experience of OS X would go down.
Not to mention that having to QA system updates with yet-another-
version of the frameworks makes things uglier as well (right now its 2
CPUs x [32 bit + 64 bit + 64 bit GC] which would become 2 CPUs x [32
bit 10.4 + 32 bit 10.5 + 32 bit 10.5 GC + 64 bit + 64 bit GC] - 6 vs
10 testing configuration). There are more than purely technical
decisions involved in shipping products.
Glenn Andreas <gandreas...>
<http://www.gandreas.com/> wicked fun!
quadrium | prime : build, mutate, evolve, animate : the next
generation of fractal art -
On Feb 17, 2008, at 8:59 AM, William Squires wrote:
> But it doesn't answer the question. Why even make the change in the
> 64-bit runtime? This would seem to hide a source of bugs, by taking
> the responsibility for providing storage away from the programmer.
> Some storage is still necessary. And besides, in order to take
> advantage of Leopard features like this one (whether on PPC or
> Intel), you should still have to link against the 10.5 SDK, so it
> would seem more reasonable to make the update to both the 32 and 64-
> bit runtimes, but only in the 10.5 SDK. Then you could update the
> 10.5 SDK (to 10.5.1) to allow for this "syntactic sugar" under both
> 32- and 64-bit.
> I mean, after all, all it means is that you're changing the default
> size of an (Integer) register in the CPU chip, and updating the OS
> to take advantage. How would this make implementing (or not
> implementing) this change any harder or easier?
Apple does not ship the Tiger version of the frameworks and runtime
with Leopard. All of the frameworks/dylibs on Leopard, while they
contain Leopard specific features, maintain backwards compatibility
with prior releases of the OS.
The changes required to support the various Modern Runtime features
found in the 64 bit version of the Leopard runtime would have required
ABI changes -- changes to the way the compiler generates code, call
sites and/or metadata -- to support. That is, it isn't just
syntactic sugar -- it changes the way Objective-C classes are
represented both in the executable and in memory.
Making a change to the ABI would break all applications that were
compiled for the old ABI.
Or it would require that Apple ship two entire copies of all
frameworks/dylibs on the system; one compiled with the 10.5 ABI and
one compiled with the 10.4-and-prior ABI.
b.bum -
On Feb 17, 2008, at 11:59 AM, William Squires wrote:
> But it doesn't answer the question. Why even make the change in the
> 64-bit runtime? This would seem to hide a source of bugs, by taking
> the responsibility for providing storage away from the programmer.
> Some storage is still necessary.
As it stands, you cannot add iVars to a base class in the 32-bit
runtime without required that all subclasses be recompiled.
This is particularly important for frameworks like AppKit. An AppKit
class cannot have an iVar added to it because it would break binary
compatibility with everyone who subclassed it. The 64-bit runtime
solves this problem.
> And besides, in order to take advantage of Leopard features like
> this one (whether on PPC or Intel), you should still have to link
> against the 10.5 SDK, so it would seem more reasonable to make the
> update to both the 32 and 64-bit runtimes, but only in the 10.5 SDK.
> Then you could update the 10.5 SDK (to 10.5.1) to allow for this
> "syntactic sugar" under both 32- and 64-bit.
> I mean, after all, all it means is that you're changing the default
> size of an (Integer) register in the CPU chip, and updating the OS
> to take advantage. How would this make implementing (or not
> implementing) this change any harder or easier?
The 32-bit runtime must remain binary compatible with all code that
was compiled and targeted for Tiger and earlier.
It is extremely desirable to be able to link against the 10.5 SDK and
still deploy your application on Tiger (after taking appropriate
measures.)
By restricting this changes to the 64-bit runtime, all binary
compatibility issues are avoided, because there are no legacy 64-bit
applications.
Jim -
On Feb 17, 2008, at 11:13 AM, Jim Correia wrote:
> On Feb 17, 2008, at 11:59 AM, William Squires wrote:other than what the base class exposes in its API (from the POV of
>
>> But it doesn't answer the question. Why even make the change in
>> the 64-bit runtime? This would seem to hide a source of bugs, by
>> taking the responsibility for providing storage away from the
>> programmer. Some storage is still necessary.
>
> As it stands, you cannot add iVars to a base class in the 32-bit
> runtime without required that all subclasses be recompiled.
??? Why should the subclasses know anything about the base class
whomever is writing the subclass code, if they follow proper OO
methodologies)? Only if I rewrite the subclass to specifically use
the new iVar should I need to recompile it.
i.e. If I have a base class A
@interface
class MyObject : NSObject <- Yeah, I know this isn't needed, just
there 'cause I'm retentive :)
{
int iMyIVar;
}
- (id) init;
- (void) printMe;
- (int) myIVar;
- (void) setMyIVar: (int) i;
@end
and I make another class B that inherits from it, then if I only use
this API (by #import "MyObject.h") in my code, I should be okay even
if someone adds a new property or method, since my code doesn't even
look at the new stuff. That is, if I do:
...
{
MyObject *myObj = [[MyObject alloc] init];
...
}
somwehere, then *myObj points to some data structure in memory (a C
struct) that contains the iVars, and a "smart" pointer to the method
implementations I can reach via the API (i.e. the public '-' methods
in the @interface section). So all my class B cares about is that a
"MySubObject *" points to a data structure, one of whose elements
(iVars) is "iMyIVar" of type (int) (because it's inherited from
MyObject), and that I can get to not only my methods, but any
inherited methods through the "smart" pointer in that data structure.
And really, I shouldn't even access the "iMyIVar" in the subclass
except through the inherited accessors (getters/setters), so I
shouldn't even need to know what iVars are in the base class, just
the accessors for them (which are methods.) So even if Apple's
software engineers decide to add an iVar to some NS framework class
(or class cluster), I shouldn't care unless I want to look at the
documentation to see what new methods (including accessors) are
available in that class. Then I'd have to recompile my subclass in
any event because I changed the code.
Right?
Now it'd be different if the REMOVED a method - that would be bad
mojo! :(
> This is particularly important for frameworks like AppKit. AnHow? And, more importantly, why? What advantage is added by hiding
> AppKit class cannot have an iVar added to it because it would break
> binary compatibility with everyone who subclassed it. The 64-bit
> runtime solves this problem.
>
the need for the storage? And what happens if you follow the older
model and still provide the storage anyway?
>> And besides, in order to take advantage of Leopard features likeadvantage of features in that SDK, not to maintain backwards
>> this one (whether on PPC or Intel), you should still have to link
>> against the 10.5 SDK, so it would seem more reasonable to make the
>> update to both the 32 and 64-bit runtimes, but only in the 10.5
>> SDK. Then you could update the 10.5 SDK (to 10.5.1) to allow for
>> this "syntactic sugar" under both 32- and 64-bit.
>> I mean, after all, all it means is that you're changing the
>> default size of an (Integer) register in the CPU chip, and
>> updating the OS to take advantage. How would this make
>> implementing (or not implementing) this change any harder or easier?
>
> The 32-bit runtime must remain binary compatible with all code that
> was compiled and targeted for Tiger and earlier.
>
> It is extremely desirable to be able to link against the 10.5 SDK
> and still deploy your application on Tiger (after taking
> appropriate measures.)
Huh? I thought the point of linking against a new SDK was to take
compatibility with the older OS features?
>
> By restricting this changes to the 64-bit runtime, all binary
> compatibility issues are avoided, because there are no legacy 64-
> bit applications.
>
> Jim
-
On Feb 17, 2008, at 9:47 AM, William Squires wrote:
>> As it stands, you cannot add iVars to a base class in the 32-bit
>> runtime without required that all subclasses be recompiled.
> ??? Why should the subclasses know anything about the base class
> other than what the base class exposes in its API (from the POV of
> whomever is writing the subclass code, if they follow proper OO
> methodologies)? Only if I rewrite the subclass to specifically use
> the new iVar should I need to recompile it.
<http://www.google.com/search?client=safari&rls=en-us&q=fragile+base
+class&ie=UTF-8&oe=UTF-8>
mmalc -
On Feb 17, 2008, at 9:47 AM, William Squires wrote:
> On Feb 17, 2008, at 11:13 AM, Jim Correia wrote:
>> On Feb 17, 2008, at 11:59 AM, William Squires wrote:
>>> But it doesn't answer the question. Why even make the change in
>>> the 64-bit runtime? This would seem to hide a source of bugs, by
>>> taking the responsibility for providing storage away from the
>>> programmer. Some storage is still necessary.
>> As it stands, you cannot add iVars to a base class in the 32-bit
>> runtime without required that all subclasses be recompiled.
> ??? Why should the subclasses know anything about the base class
> other than what the base class exposes in its API (from the POV of
> whomever is writing the subclass code, if they follow proper OO
> methodologies)? Only if I rewrite the subclass to specifically use
> the new iVar should I need to recompile it.
> i.e. If I have a base class A
It is an implementation detail.
In the legacy -- 32 bit -- runtime, each subclass effectively tacks
its instance variables onto the end of the superclass's instance
variables as if it were all one big extensible C structure. If the
superclass adds an ivar, the offset of the ivars in said structure are
thus incorrect and, unless you recompile, subclasses will read/write
from the wrong spot in memory and *boom*.
The modern -- 64 bit -- runtime fixes this particular issue.
>
>> This is particularly important for frameworks like AppKit. An
>> AppKit class cannot have an iVar added to it because it would break
>> binary compatibility with everyone who subclassed it. The 64-bit
>> runtime solves this problem.
>>
> How? And, more importantly, why? What advantage is added by hiding
> the need for the storage? And what happens if you follow the older
> model and still provide the storage anyway?
In the modern runtime, it doesn't matter if you have properties
synthesize the storage or you declare the storage explicitly, you can
still modify the superclass's inventory of instance variables --
explicitly or through synthesis -- without requiring subclasses to be
recompiled.
There is a very good reason for "hiding the storage" -- for
synthesizing the storage of an instance variable. By doing so, you
force all access to said instance variable to go through either the
synthesized setter/getter or your own implementation of the setter/
getter. Without jumping through some significant hoops, some random
bit of code external to your class isn't going to be able to diddle
the instance variables of your class directly.
>>> And besides, in order to take advantage of Leopard features like
>>> this one (whether on PPC or Intel), you should still have to link
>>> against the 10.5 SDK, so it would seem more reasonable to make the
>>> update to both the 32 and 64-bit runtimes, but only in the 10.5
>>> SDK. Then you could update the 10.5 SDK (to 10.5.1) to allow for
>>> this "syntactic sugar" under both 32- and 64-bit.
>>> I mean, after all, all it means is that you're changing the
>>> default size of an (Integer) register in the CPU chip, and
>>> updating the OS to take advantage. How would this make
>>> implementing (or not implementing) this change any harder or easier?
>>
>> The 32-bit runtime must remain binary compatible with all code that
>> was compiled and targeted for Tiger and earlier.
>>
>> It is extremely desirable to be able to link against the 10.5 SDK
>> and still deploy your application on Tiger (after taking
>> appropriate measures.)
> Huh? I thought the point of linking against a new SDK was to take
> advantage of features in that SDK, not to maintain backwards
> compatibility with the older OS features?
Linking against a new SDK provides for the ability to take advantage
of the new API provided by said SDK.
But this isn't an API issue, this is an ABI issue. The features of
the modern runtime *** REQUIRE *** a different ABI that is
incompatible with prior releases of Mac OS X.
Thus, the decision was made to only offer the modern runtime features
for 64 bit applications on Leopard and beyond. There was no binary
compatibility issues as there was no prior release of Mac OS X that
offered 64 bit Objective-C support.
b.bum -
On Feb 17, 2008, at 12:47 PM, William Squires wrote:
>> The 32-bit runtime must remain binary compatible with all code that
>> was compiled and targeted for Tiger and earlier.
>>
>> It is extremely desirable to be able to link against the 10.5 SDK
>> and still deploy your application on Tiger (after taking
>> appropriate measures.)
>
> Huh? I thought the point of linking against a new SDK was to take
> advantage of features in that SDK, not to maintain backwards
> compatibility with the older OS features?
Suppose there is a new framework feature on Leopard that I want to
take advantage of. I link against the 10.5 SDK and in my code d
if (some feature available) {
...
} else {
... some alternate code, or nothing at all ...
}
The resulting binary can, with care, still work on 10.4 and earlier.
Jim -
On Feb 17, 2008, at 12:03 PM, Bill Bumgarner wrote:
> On Feb 17, 2008, at 9:47 AM, William Squires wrote:Okay, that explains it - weird... I wonder why ObjC did that?
>> On Feb 17, 2008, at 11:13 AM, Jim Correia wrote:
>>> On Feb 17, 2008, at 11:59 AM, William Squires wrote:
>>>> But it doesn't answer the question. Why even make the change in
>>>> the 64-bit runtime? This would seem to hide a source of bugs, by
>>>> taking the responsibility for providing storage away from the
>>>> programmer. Some storage is still necessary.
>>> As it stands, you cannot add iVars to a base class in the 32-bit
>>> runtime without required that all subclasses be recompiled.
>> ??? Why should the subclasses know anything about the base class
>> other than what the base class exposes in its API (from the POV of
>> whomever is writing the subclass code, if they follow proper OO
>> methodologies)? Only if I rewrite the subclass to specifically use
>> the new iVar should I need to recompile it.
>> i.e. If I have a base class A
>
> It is an implementation detail.
>
> In the legacy -- 32 bit -- runtime, each subclass effectively tacks
> its instance variables onto the end of the superclass's instance
> variables as if it were all one big extensible C structure. If the
> superclass adds an ivar, the offset of the ivars in said structure
> are thus incorrect and, unless you recompile, subclasses will read/
> write from the wrong spot in memory and *boom*.
>
> The modern -- 64 bit -- runtime fixes this particular issue.
>
>>
>>> This is particularly important for frameworks like AppKit. An
>>> AppKit class cannot have an iVar added to it because it would
>>> break binary compatibility with everyone who subclassed it. The
>>> 64-bit runtime solves this problem.
>>>
>> How? And, more importantly, why? What advantage is added by hiding
>> the need for the storage? And what happens if you follow the older
>> model and still provide the storage anyway?
>
> In the modern runtime, it doesn't matter if you have properties
> synthesize the storage or you declare the storage explicitly, you
> can still modify the superclass's inventory of instance variables
> -- explicitly or through synthesis -- without requiring subclasses
> to be recompiled.
>
> There is a very good reason for "hiding the storage" -- for
> synthesizing the storage of an instance variable. By doing so, you
> force all access to said instance variable to go through either the
> synthesized setter/getter or your own implementation of the setter/
> getter. Without jumping through some significant hoops, some
> random bit of code external to your class isn't going to be able to
> diddle the instance variables of your class directly.
>
>>>> And besides, in order to take advantage of Leopard features like
>>>> this one (whether on PPC or Intel), you should still have to
>>>> link against the 10.5 SDK, so it would seem more reasonable to
>>>> make the update to both the 32 and 64-bit runtimes, but only in
>>>> the 10.5 SDK. Then you could update the 10.5 SDK (to 10.5.1) to
>>>> allow for this "syntactic sugar" under both 32- and 64-bit.
>>>> I mean, after all, all it means is that you're changing the
>>>> default size of an (Integer) register in the CPU chip, and
>>>> updating the OS to take advantage. How would this make
>>>> implementing (or not implementing) this change any harder or
>>>> easier?
>>>
>>> The 32-bit runtime must remain binary compatible with all code
>>> that was compiled and targeted for Tiger and earlier.
>>>
>>> It is extremely desirable to be able to link against the 10.5 SDK
>>> and still deploy your application on Tiger (after taking
>>> appropriate measures.)
>> Huh? I thought the point of linking against a new SDK was to take
>> advantage of features in that SDK, not to maintain backwards
>> compatibility with the older OS features?
>
> Linking against a new SDK provides for the ability to take
> advantage of the new API provided by said SDK.
>
> But this isn't an API issue, this is an ABI issue. The features of
> the modern runtime *** REQUIRE *** a different ABI that is
> incompatible with prior releases of Mac OS X.
>
> Thus, the decision was made to only offer the modern runtime
> features for 64 bit applications on Leopard and beyond. There was
> no binary compatibility issues as there was no prior release of Mac
> OS X that offered 64 bit Objective-C support.
>
> b.bum
-
Le 17 févr. 08 à 19:52, William Squires a écrit :
>
> On Feb 17, 2008, at 12:03 PM, Bill Bumgarner wrote:
>
>> On Feb 17, 2008, at 9:47 AM, William Squires wrote:
>>> On Feb 17, 2008, at 11:13 AM, Jim Correia wrote:
>>>> On Feb 17, 2008, at 11:59 AM, William Squires wrote:
>>>>> But it doesn't answer the question. Why even make the change in
>>>>> the 64-bit runtime? This would seem to hide a source of bugs, by
>>>>> taking the responsibility for providing storage away from the
>>>>> programmer. Some storage is still necessary.
>>>> As it stands, you cannot add iVars to a base class in the 32-bit
>>>> runtime without required that all subclasses be recompiled.
>>> ??? Why should the subclasses know anything about the base class
>>> other than what the base class exposes in its API (from the POV of
>>> whomever is writing the subclass code, if they follow proper OO
>>> methodologies)? Only if I rewrite the subclass to specifically use
>>> the new iVar should I need to recompile it.
>>> i.e. If I have a base class A
>>
>> It is an implementation detail.
>>
>> In the legacy -- 32 bit -- runtime, each subclass effectively tacks
>> its instance variables onto the end of the superclass's instance
>> variables as if it were all one big extensible C structure. If the
>> superclass adds an ivar, the offset of the ivars in said structure
>> are thus incorrect and, unless you recompile, subclasses will read/
>> write from the wrong spot in memory and *boom*.
>>
>> The modern -- 64 bit -- runtime fixes this particular issue.
>>
> Okay, that explains it - weird... I wonder why ObjC did that?
That's not an obj-c issue. That's a runtime and compiler issue. If you
want to know why the OS X runtime did that, you will have to go back
to the NeXT's days. -
On Feb 17, 2008 1:03 PM, Bill Bumgarner <bbum...> wrote:
In the legacy -- 32 bit -- runtime, each subclass effectively tacks
> its instance variables onto the end of the superclass's instance
> variables as if it were all one big extensible C structure. If the
Okay, I can see how the basic assumption of one big continuous block of
memory might be limiting.
But, having said that... :-)
> superclass adds an ivar, the offset of the ivars in said structure are
> thus incorrect and, unless you recompile, subclasses will read/write
> from the wrong spot in memory and *boom*.
Why would the parent's size be hard-coded? You can get the size of the
parent at run time, by dereferencing a couple of levels into isa. All the
compiler would have to do is emit code that walks down isa to get the
parent's size, and add it to self to establish a base address. The only
hard-coded offsets would then be relative to that base, for the current
class' own ivars.
Changing the size of the parent class wouldn't break such a scheme, so far
as ordinary usage goes. People playing games with sizeof() or @defs deserve
whatever breakage they get. :-)
Doesn't the current (I refuse to call it "legacy" quite yet...) 32-bit
compiler emit code like that when ivars are accessed?
sherm-- -
On Feb 17, 2008, at 10:52 AM, William Squires wrote:
> Okay, that explains it - weird... I wonder why ObjC did that?
When Objective-C was created, the targeted machines had relatively
little memory -- 4MB or less, typically.
As such, every single byte that could be saved was valuable. So, as
a simple extension of C, Objective-C classes are really just a
glorified C structure that is extended across subclasses and has a
slot at the head that can point to the class of the structure.
Simple. Elegant. Compact. Easy to implement. And prone to the
fragile base class problem.
While memory is still at a premium, eating a couple of pointers worth
of memory to solve the fragile base class problem is now a worthwhile
tradeoff.
It would have been nice if this change could have been made in the
10.0 timeframe when there wasn't a binary compatibility issue
preventing adoption in 32 bits. But, at the time, there were other
priorities that out weighed solving this particular problem.
b.bum -
On Feb 17, 2008, at 12:03 PM, Sherm Pendley wrote:
> Why would the parent's size be hard-coded? You can get the size of
> the parent at run time, by dereferencing a couple of levels into
> isa. All the compiler would have to do is emit code that walks down
> isa to get the parent's size, and add it to self to establish a base
> address. The only hard-coded offsets would then be relative to that
> base, for the current class' own ivars.
>
> Changing the size of the parent class wouldn't break such a scheme,
> so far as ordinary usage goes. People playing games with sizeof() or
> @defs deserve whatever breakage they get. :-)
>
> Doesn't the current (I refuse to call it "legacy" quite yet...) 32-
> bit compiler emit code like that when ivars are accessed?
To dive a little deeper, consider the instance variables for NSView,
including inherited ivars. Well, a subset, really:
@interface NSObject <NSObject> {
Class isa;
}
@interface NSResponder : NSObject <NSCoding>
{
id _nextResponder;
}
@interface NSView : NSResponder
{
NSRect _frame;
NSRect _bounds;
id _superview;
id _subviews;
NSWindow *_window;
}
Within the legacy runtime ;), the memory for NSView looks just like a
C struct with this layout:
struct NSViewLikeStruct {
Class isa;
id _nextResponder;
NSRect _frame;
NSRect _bounds;
id _superview;
id _subviews;
NSWindow *_window;
};
So, in the implementation of an NSView, an access to an instance
variable -- say _subviews -- is compiled down to something equivalent
to:
((struct NSViewLikeStruct *) aView)->_subviews
Now, if an instance variable is added to NSObject or NSResponder and
the subclasses are not compiled, the above code will have the wrong
offset.
This is fragile, but allows instances to be allocated as a single
chunk of memory while also reducing the amount of metadata and/or
indirection required to get at any given instance variable's slot.
To fix the issue, it has to be done partially at runtime and requires
a different layout for the instances...
b.bum -
On 17 Feb '08, at 12:03 PM, Sherm Pendley wrote:
> Why would the parent's size be hard-coded? You can get the size of the
> parent at run time, by dereferencing a couple of levels into isa.
> All the
> compiler would have to do is emit code that walks down isa to get the
> parent's size, and add it to self to establish a base address. The
> only
> hard-coded offsets would then be relative to that base, for the
> current
> class' own ivars.
This has been done before, most notably in IBM/Apple's "SOM" runtime
that was used in OpenDoc in the mid-'90s. The main drawback is that it
becomes more expensive to access instance variables. Instead of
indexing off a constant offset from the object pointer, you have to
call a runtime function that returns a pointer to the class's ivars,
and index off that.
It also adds some complexity to both the compiler and the runtime, to
deal with the dynamic location of the ivars.
The "Fragile Base Class" problem is common to many object runtimes. C+
+ has it even worse, in that the normal vtable-based runtime makes it
impossible to add even *methods* to a base class without breaking
subclasses. It turns out that fragile methods are much more of a
problem than fragile instance variables; it's fairly easy to reserve a
few unused ivars in advance and use them later on. So Obj-C has been
able to work quite well in dynamic libraries, while C++ has usually
fallen on its face. But it's nice that this last restriction is now
lifted in the 64-bit environment.
(Scripting languages don't generally suffer from this. Most of them
store an object's ivars in a hashtable, which is much slower but much
more flexible, so you can do crazy stuff like adding ivars to
individual instances.)
—Jens



