Wednesday, April 24, 2013

Objective C's C#'s lambda

So we are missing C#'s Where lambda, which allows us to generalize a filter pattern, instead of creating new function everytime we need a new kind filter. On my last post about C#'s extension method, we have defined a function that filters all the odd elements, and everytime we have a new kind of filter, say get all the even elements, we will need to introduce another method called evenElements, think of all possible variations of filter and duplicated amount of code in those functions.


How about instead of creating a new method whenever a new set of condition would be required, we generalize the method's functionality and allows us to pass any kind of filters.

Luckily for C# transitioners, Objective C has a lambda, which is called blocks.


So with blocks, it allows us to create building blocks for generalized routine, e.g. filter.


So instead of creating another method that filters all the even numbers, we will just create a generalized lambda method that allows us to pass any filter condition. First, we should create the signature of the lambda in the .h file:

-(NSMutableArray*) where: (bool (^)(NSNumber *)) expr;



This is the lambda parameter on NSMutableArray's where Category(Extension Method in C#'s parlance):

(bool (^)(NSNumber *)) expr;


In Objective-C, the method's parameter has the following syntax, open parenthesis, type, close parenthesis, and the name of the parameter. So the name of the parameter is expr. So our type is:

bool (^)(NSNumber *)


The caret(^) denotes that the type is a lambda type, and that lambda signature allows us to receive an NSNumber parameter, and allows us to return a boolean type. So that's just it. Can't take but notice that it's a bit ironic that given the Objective-C's messaging mechanism (where the message's parameter is denoted by a colon), its lambda syntax takes the function signature form (similar to JavaScript lambda or C#'s Func/delegate) instead of its usual messaging mechanism syntax. I think Objective-C lambda code will look very convoluted if its lambda syntax resembles Objective-C messaging rather than the simpler function signature.


Here's the implementation of the lambda signature above, note that we simply invoke the expr by adding an open parenthesis, parameter, and close parenthesis. Which is a homey function syntax, not the messaging style syntax of Objective-C

-(NSMutableArray*) where: (bool (^)(NSNumber *)) expr {
    NSMutableArray *x = [NSMutableArray array];
    
    
    for(NSNumber *number in self) {
        if (expr(number)) { // we invoke the expr lambda
            [x addObject: number];
        }
    }
    
    return x;
}


If you are curious, yes this doesn't work:
if ([expr number]) {
    [x addObject: number];
}


Then here's how we use the lambda implementation:

void demoArray()
{
    @autoreleasepool {
        
        NSMutableArray *items = [NSMutableArray array];
        
        [items addObject: [NSNumber numberWithInteger:42]];

        
        [items addObject: [NSNumber numberWithInteger:11]];
        [items addObject: [NSNumber numberWithInteger:5]];
        [items addObject: [NSNumber numberWithInteger:1976]];
        
        
        for(NSNumber *number in [items oddElements]) {
            printf("\n%d", number.intValue);
        }
        
        
        
        printf("All even numbers:\n");
        for(NSNumber *number in [items where: ^(NSNumber *n) { return (bool)(n.intValue % 2 == 0 ); } ]) {
            printf("\n%d", number.intValue);
        }
    
    }
}


Output:
All even numbers:

42
1976


We want to list all odd numbers less than 100?
void demoArray()
{
    @autoreleasepool {
        
        NSMutableArray *items = [NSMutableArray array];
        
        [items addObject: [NSNumber numberWithInteger:42]];

        
        [items addObject: [NSNumber numberWithInteger:11]];
        [items addObject: [NSNumber numberWithInteger:5]];
        [items addObject: [NSNumber numberWithInteger:1976]];
        
        
        
        for(NSNumber *number in [items where: ^(NSNumber *n) { return (bool)(n.intValue % 2 == 1 && n.intValue <= 100 ); } ]) {
            printf("\n%d", number.intValue);
        }
    
    }
}
Output:
11
5

No comments:

Post a Comment