PDA

View Full Version : Question about Obj-C




TheLee
Dec 17, 2006, 02:38 PM
Let's say I have something like this:

@interface Foo : NSObject {
Bar *object;
}

- (Bar *) object;
@end

@implementation Foo

- (Bar *) object {
return object;
}
@end


Why can't I do something like:
&[someFoo object]
to get a Bar**? It's really annoying since I'll have methods that want a double pointer (like a char ** or some custom double pointer), but I can't just directly go "&[someFoo object]" to get a double pointer out of an object. Instead, I have to do something ugly like:

Bar *temp;
temp = [someFoo object];
blah( &temp );
[someFoo setObject:*temp];

because

blah( &[someFoo object] );

gives all sorts of ugly lvalue compile error messages.



robbieduncan
Dec 17, 2006, 06:20 PM
You are making unwarranted assumptions with the implementation of Obj-C. You assume that a method is simply a function. Sending a message is not the same as sending a message.

[someFoo object] is simply syntactic sugar. This is really a call to the runtime function objc_msgSend (http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html). This method ALWAYS returns id.

It seems that a cast would solve this but it doesn't seem to...

robbieduncan
Dec 17, 2006, 06:28 PM
OK looking at this further it appears that this may be due to the return type. The runtime reference tells us that when the returned valued from the method call is a structure then the runtime function

void objc_msgSend_stret(void * stretAddr, id theReceiver, SEL theSelector, ...);

will be called. But what is an Object? Well at a really low level I believe it a structure. So this function will be used. Note that the returned values is actually done by manipulating the data at the address in the first pointer. It's not the return. Which explains exactly why your syntax doesn't work.

As usual it's all in the documentation :D

lazydog
Dec 18, 2006, 06:55 AM
Why can't I do something like:
&[someFoo object]
to get a Bar**?


Because it's returning the ***value*** of the pointer variable 'object' and you can't take the address of a value.

What you could do is this:-

- (Bar **) object {
return & object;
}

Hope this helps

b e n

robbieduncan
Dec 18, 2006, 07:13 AM
Because it's returning the ***value*** of the pointer variable 'object' and you can't take the address of a value.

What you could do is this:-

- (Bar **) object {
return & object;
}

Hope this helps

b e n

Did you read my post above? It's nothing to do with taking the address of a value. It's entirely due to the way the compiler turns Objective-C syntax into C function calls into the runtime.

lazydog
Dec 18, 2006, 08:16 AM
Yes I did thanks… thanks for highlighting exactly why & [ object message ] does not compile.

But, in my opinion, your explanation didn't really help with what he was trying to do. No disrespect to TheLee but even if his interpretation of & [ object message ] was correct he would still have a misunderstanding of lvalues and pointers. I was only trying to point this out and suggest a solution.

b e n

robbieduncan
Dec 18, 2006, 08:30 AM
Fair enough. I'm not actually convinced you are correct though. If we assume that message passing worked how the OP thought it did (so the same as C function calling) then a message with a signature of - (Bar *) ... returns a pointer to a Bar, not an actual Bar value. You should be able to take the address of a (Bar *) which is why using a temp variable works.

Oats
Dec 18, 2006, 09:06 AM
Fair enough. I'm not actually convinced you are correct though. If we assume that message passing worked how the OP thought it did (so the same as C function calling) then a message with a signature of - (Bar *) ... returns a pointer to a Bar, not an actual Bar value.

The function will return a VALUE, which is a pointer to a Bar. If you try to get the address of that value before it is stored in a local or global variable, it seems to me it could quickly become invalid. In other words, you may receive a pointer to that value, but the memory for that value may be deallocated and re-assigned soon after the message completes. It would probably work if you were sure to copy the value to a more permanent location before getting its address:


aptr = [someFoo object];
aptrptr = &aptr

robbieduncan
Dec 18, 2006, 09:12 AM
The function will return a VALUE, which is a pointer to a Bar. If you try to get the address of that value before it is stored in a local or global variable, it seems to me it could quickly become invalid. In other words, you may receive a pointer to that value, but the memory for that value may be deallocated and re-assigned soon after the message completes. It would probably work if you were sure to copy the value to a more permanent location before getting its address:


aptr = [someFoo object];
aptrptr = &aptr

That does work as noted by the OP. Whether the address of the returned pointer becomes invalid is not up to the compiler to worry about here: it's up to the programmer. If we follow normal Cocoa style then the returned object will be autoreleased and will, therefore, get deallocated at some point in the future (probably at the end of this run loop), but not before this method ends. In your example the address taken on the second line could just as easily become invalid as the first like does nothing to alter the address or retain the object, it simply causes aptr to point at the address in the returned pointer.

lazydog
Dec 18, 2006, 09:23 AM
With…

- (Bar *) object { return object; }

the value of the pointer is returned. This is a memory address. So, in the spirit of the original post, &[someFoo object] would be interpreted as something like & 0x1235678 which can't be done. In other words

Bar** obj = & [someFoo object] ;

would be illegal and generate an lvalue error.


I really think the best thing the OP can do is…

-(Bar**) object { return & object ; }

This is okay,

Bar* obj = [someFoo object];
Bar** obj_p = & obj ;

but not if you plan on using obj_p if obj should ever go out of scope.

b e n

HiRez
Dec 18, 2006, 09:37 AM
Not sure why the OP would need such an unholy beast, but it does seem logical to me that is should work as he thought it would. The Obj-C runtime should do that translation because I don't see how it conflicts with anything else. Then again, while using a temp variable might be a little ugly and inefficient, it doesn't seem like that much of a PITA to type it out that way. You could even wrap the whole little mess into a generic utility function to make it more convenient for yourself if you need to call it often.

Oats
Dec 18, 2006, 09:47 AM
In your example the address taken on the second line could just as easily become invalid as the first like does nothing to alter the address or retain the object, it simply causes aptr to point at the address in the returned pointer.

In my example, the address of "aptr" will not become invalid until "aptr" is out of scope, which the programmer has control over. In C++, the compiler would probably let you get the address of a returned value, but it would likely be invalid, because you are trying to get the address of a return value that has a very short time to live. The object holding the return value likely gets deallocated by the time the next line of code is called. It is possible that the objective-C compiler generates errors and warnings to protect the programmer from this mistake.

This is similar to what lazydog is saying... but though a VALUE technically has an address somewhere in memory, unless you control the scope of that VALUE, you should never attempt to use such an address.

Nutter
Dec 18, 2006, 11:36 AM
The object holding the return value likely gets deallocated by the time the next line of code is called.

Yes, but what if you're using the return value in the same line only?
For instance:

MyFunction(&[someFoo object]);

I suppose this is the kind of usage the OP had in mind.

Besides robbieduncan's explanation of why the runtime doesn't allow this, what's wrong with it?

lazydog
Dec 18, 2006, 01:51 PM
[QUOTE=Nutter;3161075
Besides robbieduncan's explanation of why the runtime doesn't allow this, what's wrong with it?[/QUOTE]

I would suggest for the same reason why you wouldn't expect this to compile:-

int get_an_int_value() { return 123 ; }



int* ptr = & get_an_int_value() ;

b e n