Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

TheLee

macrumors member
Original poster
Aug 5, 2006
71
0
Let's say I have something like this:
Code:
@interface Foo : NSObject {
    Bar *object;
}

- (Bar *) object;
@end

@implementation Foo

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

Why can't I do something like:
Code:
&[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:
Code:
Bar *temp;
temp = [someFoo object];
blah( &temp );
[someFoo setObject:*temp];
because
Code:
blah( &[someFoo object] );
gives all sorts of ugly lvalue compile error messages.
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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. This method ALWAYS returns id.

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

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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

macrumors 6502a
Sep 3, 2005
709
6
Cramlington, UK
Why can't I do something like:
Code:
&[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

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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

macrumors 6502a
Sep 3, 2005
709
6
Cramlington, UK
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

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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

macrumors regular
Jan 8, 2003
194
1
New York
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:

Code:
aptr = [someFoo object];
aptrptr = &aptr
 

robbieduncan

Moderator emeritus
Jul 24, 2002
25,611
893
Harrogate
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:

Code:
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

macrumors 6502a
Sep 3, 2005
709
6
Cramlington, UK
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

macrumors 603
Jan 6, 2004
6,265
2,629
Western US
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

macrumors regular
Jan 8, 2003
194
1
New York
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

macrumors 6502
Mar 31, 2005
432
0
London, England
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?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.