Question about Obj-C

Discussion in 'Mac Programming' started by TheLee, Dec 17, 2006.

  1. macrumors member

    Joined:
    Aug 5, 2006
    #1
    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.
     
  2. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    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...
     
  3. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #3
    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
     
  4. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #4

    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
     
  5. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #5
    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.
     
  6. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #6
    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
     
  7. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #7
    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.
     
  8. macrumors regular

    Joined:
    Jan 8, 2003
    Location:
    New York
    #8
    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
     
  9. Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #9
    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.
     
  10. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #10
    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
     
  11. macrumors 601

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #11
    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.
     
  12. macrumors regular

    Joined:
    Jan 8, 2003
    Location:
    New York
    #12
    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.
     
  13. macrumors 6502

    Joined:
    Mar 31, 2005
    Location:
    London, England
    #13
    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?
     
  14. macrumors 6502a

    Joined:
    Sep 3, 2005
    Location:
    Cramlington, UK
    #14
     

Share This Page