Can someone please explain why this doesn't generate an error?

Discussion in 'Mac Programming' started by chrono1081, Oct 30, 2011.

  1. chrono1081 macrumors 604

    chrono1081

    Joined:
    Jan 26, 2008
    Location:
    Isla Nublar
    #1
    Hi guys,

    I'm relearning Objective-C using Steve Kochans book and I don't understand why the one program doesn't generate an error. I assure you the classes that are referenced are correct but check out the main function:

    Code:
    int main (int argc, char*argv[])
    {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
        Fraction *aFraction = [[Fraction alloc] init];
        Fraction *sum = [[Fraction alloc] init], *sum2;
        int i, n, pow2;
        
        [sum setTo: 0 over: 1]; //Set 1st fraction to 0
        
        NSLog(@"Enter your value for n: ");
        scanf("%i", &n);
        
        pow2 = 2;
        for(i = 1; i <= n; ++i)
        {
            [aFraction setTo: 1 over: pow2];
            sum2 = [sum add: aFraction];
            [B][sum release];[/B] [B][COLOR="Red"]//Why does this work? Is it scope related?[/COLOR][/B]
            [B]sum = sum2;[/B] [B][COLOR="red"]//Wait! sum was just released![/COLOR][/B]
            pow2 *= 2; 
        }
        
        NSLog(@"After %i iterations, the sum is %g", n, [sum convertToNum]);
        [aFraction release];
        [sum release];
        
        
        [pool drain];
        return 0;
    }
    
    I highlighted the section I was confused on. Notice how I release sum, then the line right after I assign sum a value! How does this not result in an access error?

    Sum is not being declared within the loop so once it is released it should be gone correct? If I try and release and reassign sum outside of the loop in the same way that is done within the loop then it does generate an error. How come the sum inside the loop isn't doing the same?

    The only conclusion I can come to is it is scope related. Can someone please clarify this for me?
     
  2. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #2
    What I think is going on is that [Fraction add] returns a newly allocated Fraction instance. The original is not needed afterwards, so it's released, and the result returned from add is assigned to the same variable (it's fine to "overwrite" sum this way).

    This is confusing, because it doesn't follow the memory management naming conventions. "Add" should probably have been called "createFractionByAddingFraction" or something ugly like that. In fact, I would expect that a function "add" would not return anything at all, and add its argument in-place. That way, this whole switcheroo would have been avoided.

    I don't particularly like this aspect of Objective-C; and I wish you could return objects by value, like in C++.
     
  3. chrono1081, Oct 30, 2011
    Last edited: Oct 30, 2011

    chrono1081 thread starter macrumors 604

    chrono1081

    Joined:
    Jan 26, 2008
    Location:
    Isla Nublar
    #3
    That is exactly what add does! I'm usually programming in C++ and this part of Objective-C is confusing me. Thanks for the explanation :)
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    Except "create" isn't one of the magic prefixes in Objective-C. It's only a magic prefix in Core Foundation.
    Memory Management Guide:
    You create an object using a method whose name begins with “alloc”, “new”, “copy”, or “mutableCopy”.​
     
  5. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #5
    You have to distinguish between objects and variables. When you call for example [[xxx alloc] init] an object is created, and that object exists somewhere, but nobody cares exactly where. init also returns a pointer to that object, and you can store that pointer to a variable. The variable is just a signpost pointing you to where the object is, it is not itself the object itself.

    So when you call [sum release], this is what happens: sum is just a variable containing a pointer to an object. That object is released. The variable sum is unchanged, it contains the pointer. The object might have disappeared because it was released, and in that case the pointer stored in sum is now rubbish. Like a signpost to a house that has just been pulled down. The house is gone, but the signpost is unchanged.

    And because the variable sum is still there, you can store a different pointer in it.

    What happens if you store a different pointer without calling [sum release]? In that case, the object is still there, but sum doesn't point to it anymore. If that pointer isn't stored anywhere else, then you just lost track of the object. Like a lost wallet, your money and credit card are still in the wallet, but you can't use them anymore because the wallet is gone.
     
  6. chrono1081 thread starter macrumors 604

    chrono1081

    Joined:
    Jan 26, 2008
    Location:
    Isla Nublar
    #6
    Thanks so much guys! It makes MUCH more sense now :) I wasn't thinking as sum as a pointer to an object :eek:
     
  7. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #7
    Ah yes - I knew the "create" wasn't right, I just couldn't remember the real prefix. "newFractionByAddingFraction" it is, then. Thanks for the correction.
     
  8. jiminaus, Oct 30, 2011
    Last edited: Oct 30, 2011

    jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #8
    Actually no. newFractionByAddingFraction should be a class method, not an object method. It should be equivalent to [[Fraction alloc] initByAddingFraction:], and that doesn't make sense.

    I think the add object method is correct, it's just that the semantics of the method are wrong. The add method should return an autoreleased object.
     
  9. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #9
    It would be a bit sad if the art of memory management were completely lost due to the convenience of ARC. This bit of teaching is on the verge of becoming irrelevant.

    (Personally, I think I would create a MutableFraction subclass and bypass the whole object creation cycle here, though that is kind of beside the point.)
     
  10. Sander macrumors 6502

    Joined:
    Apr 24, 2008
    #10
    Given NSString's "stringByAppendingString" it should be "fractionByAddingFraction", no?

    I agree about the autoreleased object though - otherwise you can't nest expressions since you can't release anonymous temporaries.

    I stick to my point that lacking proper value semantics, constructions like this look very fragile and clumsy to me.
     
  11. jiminaus macrumors 65816

    jiminaus

    Joined:
    Dec 16, 2010
    Location:
    Sydney
    #11
    That would be a good enough precedent for me. Just as long as it too returns an autoreleased object.

    This would also free up the add method to be used in the MutableFraction subclass suggested by Sydde.
     

Share This Page