Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful
Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful
- Subject: Re: Use of Mac OS X 10.5 / Leopards Garbage Collection Considered Harmful
- From: John Engelhart <email@hidden>
- Date: Thu, 7 Feb 2008 01:14:02 -0500
On Feb 6, 2008, at 10:01 PM, glenn andreas wrote:
On Feb 6, 2008, at 7:48 PM, John Engelhart wrote:
int main(int argc, char **argv) {
NSObject *stackObject = NULL;
stackObject = alloca(sizeof(stackObject));
This, of course, just alloced something the size of a pointer, which
may not be the real size of the class (if it were something other
than NSObject)
Opps, you're right. I clearly meant NSObject, as the memset line
below shows. You'll note that changing the alloca line from
stackObject to NSObject works just fine.
memset(stackObject, 0, sizeof(NSObject));
stackObject->isa = [NSObject class];
NSLog(@"stackObject: %@", stackObject);
}
[johne@LAPTOP_10_5] /tmp% gcc -framework Foundation -o tst tst.m
tst.m: In function 'main':
tst.m:7: warning: instance variable 'isa' is @protected; this will
be a hard error in the future
[johne@LAPTOP_10_5] /tmp% ./tst
2008-02-06 20:17:16.306 tst[18320:807] stackObject: <NSObject:
0xbffff380>
As the address clearly shows, this is an object on the stack.
Although I have had to manually initialize the object, it is
exactly, or very close to, what "NSObject stackObject" would have
created.
The biggest problem is that the above example shows something that
isn't usable - it's sterile. You can't pass it to other routines
(due to memory management requirements), you may not even be able to
call all the methods of the object (since they may pass the
themselves as parameters to other objects which invoke memory
management requirements). Only if you wrote your own entire
hierarchies could you use such a construction (or if you implemented
full closures, which is even more difficult in a C based
language) . There's a whole raft of semantics associated with Cocoa
objects (above and beyond anything that whatever version of the
objective-c runtime may require).
I'm pretty sure I was clear that this is "not really a good idea in
reality." It is, unlike you stated, possible to do.
If you can't use the object, have you actually created it?
You can use the object. It remains live until the stack frame pops.
It will work exactly like any other object. The "deallocation" of the
object is tricky, but I'm sure you could still pull it off if you
really wanted.
As you can see, and the code clearly demonstrates, my original
assertion stands.
One could also manually construct a C++ vtable and set up all the
magic "behind the scenes" plumbing that a C++ object has, but that
doesn't mean that C++ object are ' synonymous for "Structs" ' either.
The point is that they are not synonymous for structs - if they
were, you could replace one with the other, and both Objective-C and
C++ objects have additional semantic requirements.
You can replace one for the other, see above. The GCC compiler stops
you from doing this because it's really not a good idea in practice.
There are other Objective-C implementations that allow stack based
objects exactly as you describe. I can't remember which one it was
off the top of my head, it might have been poc.
This is a literal "NSObject stackObject;", if it helps any:
#import <Foundation/Foundation.h>
int main(int argc, char **argv) {
struct { @defs(NSObject) } stackObject;
memset(&stackObject, 0, sizeof(NSObject));
stackObject.isa = [NSObject class];
NSLog(@"stackObject: %@", &stackObject);
}
[johne@LAPTOP_10_5] /tmp% gcc -framework Foundation -o tst tst.m
[johne@LAPTOP_10_5] /tmp% ./tst
2008-02-07 00:04:20.477 tst[18686:807] stackObject: <NSObject:
0xbffff398>
[johne@LAPTOP_10_5] /tmp%
I suppose I could go through all the trouble of putting together
initialization and deallocation methods as part of a subclass, or
category override, that specifically dealt with stack "allocation" and
"deallocation". I could even get crafty and have dealloc check to see
if self is an pointer that's on the stack and call the stack dealloc
code, and the standard dealloc code otherwise.
Honestly though, I'm not sure how much more plain I can make it. You
said:
You misunderstand what Objective C is, and how it works. "Objects"
is synonymous for "Structs".
If that were true, you'd be able to declare objects as local
variables (as opposed to as pointers to structures):
NSPoint aPoint; // <-- NSPoint = struct, legal
NSString aString; // <-- NSString = object, Illegal
Yet, as the code above plainly shows, "struct { @defs(NSObject) }
stackObject;" has declared an object as a local variable, even passed
to NSLog() to print its description, proving that's it's a bona-fide,
useable object, and that the keyword "struct" makes it obvious that an
"object" is just a "struct".
How about "Objects" is synonymous for "struct objc_object"s ? And
since struct objc_object is typedefed to "*id", that makes it pretty
literal.
Does this help at all?
#import <Foundation/Foundation.h>
typedef struct { @defs(NSObject) } NSObject_;
int main(int argc, char **argv) {
NSObject_ stackObject;
memset(&stackObject, 0, sizeof(NSObject));
stackObject.isa = [NSObject class];
NSLog(@"stackObject: %@", &stackObject);
}
[johne@LAPTOP_10_5] /tmp% gcc -framework Foundation -o tst tst.m
[johne@LAPTOP_10_5] /tmp% ./tst
2008-02-07 00:28:47.784 tst[18734:807] stackObject: <NSObject:
0xbffff398>
I've had to add an underscore to prevent namespace collision, but....
I'm not really sure how else I can explain it.
As you can see, it's very clear where "isa" comes from.
Subclassing an object has the effect of "pasting" your ivar
declarations at the end of the class you're inheriting from, and
forms the cause of "fragile classes" since a struct effectively
becomes pointer + offset, and changing a struct requires
recompiling code to update those offsets.
Except, of course, for 64 bit Objective-C 2.0 which doesn't have
these problems (which makes the exercise of trying to allocate it on
the stack even more problematic).
Yes, as I have noted, the ObjC 2.0 64 bit ABI/API is different. This
is dealing with the 32 bit version, which has been around since the
80's.
So, no, there are no magic invisible members.
But there are semanticly required members that aren't in "plain"
structs.
Honestly, I don't follow. What is a "plain" struct?
struct objc_object {
void *isa;
};
Is that not a "plain" struct? And what do you mean by "semantically
required members"?
#import <Foundation/Foundation.h>
typedef struct { char letters[4]; } NSObject_;
int main(int argc, char **argv) {
NSObject_ stackObject;
memset(&stackObject, 0, sizeof(NSObject_));
void *classPtr = [NSObject class];
memcpy(stackObject.letters, &classPtr, sizeof(void *));
NSLog(@"stackObject: %@", &stackObject);
}
[johne@LAPTOP_10_5] /tmp% gcc -framework Foundation -o tst tst.m
[johne@LAPTOP_10_5] /tmp% ./tst
2008-02-07 00:37:57.632 tst[18799:807] stackObject: <NSObject:
0xbffff398>
Sure, a bit of square peg in to a round hole abuse to get the class
ptr copied over.... but.. No isa here, yet it works.
I suppose pedantically one could argue that in order for something to
be an "object", it would have to have the layout of a particular kind
of struct... but I think that's pushing things a little far, and in
the end, whatever the layout, that layout is declared as a struct.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden