Blocks vs function pointers question


#1

maybe its just been too long since i did heavy duty C++ programming but I thought for sure that any function retained all objects, primitive or not, until that function or method was done and was removed from the stack. If I have a function pointer doesn’t this pointer stay alive for as long as its parent function lives? sorry for the confusion here.

also since you have already declared your typedef as ^ArrayEnumeratedBlock…why would need to repeat that argument list down within the block?

shouldn’t you be able to do:

devowelizer{

};
???

  • since devowelizer was declared now as a type and it should i would think be able to know about the types arguments. No biggie just brainstorming here. Just makes it a bit more confusing I think.

Lastly, why wouldn’t I, maybe by nature, just choose to declare and implement a method that would be passed a message(a string) and use that method to remove all the vowels? perhaps there would be a file with tons of words or sentences and i would use that loop to call this method to return back the string without the vowels or perhaps write the new strings to a file. This way i could reuse this method down the road in another application without having to worry about where the string comes from - i.e. code reuse. Again sorry for the many questions… just trying to get my head around it all. :smiley:


#2

Blocks can see (and capture) local information, just as functions can see global information. This makes it possible to create and reuse code locally in ways that’s harder to do with functions.

Here is a simple example:

//  main.mm

#import <iostream>
#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
    int (^Usage)(void) = ^ {
        const char *pname = strrchr (argv [0], '/');
        pname = pname ? pname + 1 : pname;
        std::cerr << "Usage: " << pname << " <N1> <N2>" << std::endl;
        return 1;
    };
    
    if (argc != 3)
        return Usage ();
    
    // ...
    
    return 0;
}

#3

I’m just learning blocks after a long layoff from heavy-duty C/C++ programming, too, but I’ll take a shot at these questions.

Your understanding of function pointers is correct. Where blocks differ is that if the block references a pointer defined outside of the block, the data that pointer references will be copied so that the data is guaranteed to remain available for the life of the block. The following pseudocode demonstrates why this might be important.

Allocate memory for an object A and assign it some values
Define a code block that accesses object A. This will create a copy of object A that the code block will reference.
Call the code block (which access its copy of object A)
Back in the program, outside of the code block, release the memory for object A
Call the code block. If the block accessed object A (like a function pointer would), there would be a problem because its memory had been released. But because it accesses its copy of object A, it still works.

Of course, accessing a variable outside of the block seems to me to violate encapsulation. Good programming practice suggests that you really shouldn’t be accessing that external variable. If you need the variable, you should pass it into the block as an argument.

A second problem seems to be that after the block makes its copy of object A, any object A changes made outside of the block will not be seen by the block’s copy.

As I said, I’m just learning blocks myself now, so all this should be verified. A simple test program that follows the above pseudocode should be a sufficient test.

To your second question: I, too, would think that something like this would be possible:

typedef void    (^ArrayEnumerationBlock)( id, NSUInteger, BOOL * );

        [ oldStrings enumerateObjectsUsingBlock: ArrayEnumerationBlock{ ... } ];

But I wasn’t able to get the compiler to accept it. Will have to do more research at some future date…

Finally, as for creating a method to do the work of the book’s code block: I think you could do that and, in fact, in this situation, that is arguably a more appropriate solution. There are many ways to resolve issues like this. But if the author had solved this problem with a method, that would have produced a pretty bad example of a code block. :smiley: I think code blocks are mainly and most appropriately used in situations like the author mentioned, i.e., when writing an event handler/delegate/notification and you want to keep the handler code close to where you’re hooking into the event, as in the chapter’s second challenge.