Skip to content

Instantly share code, notes, and snippets.

@ole
Created February 11, 2013 15:20
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ole/4755072 to your computer and use it in GitHub Desktop.
Save ole/4755072 to your computer and use it in GitHub Desktop.
FunctionalBankAccount: a simple implementation of a blocks-based object model in (Objective-)C, inspired by a similar Scheme implementation in "Structure and Interpretation of Computer Programs". See http://oleb.net/blog/2013/02/building-blocks-based-object-system-in-objective-c/ for an explanation.
#import <Foundation/Foundation.h>
typedef id(^BankAccount)(char *cmd);
typedef id(^CurrentBalanceMethod)(void);
typedef id(^DepositMethod)(double);
typedef id(^WithdrawMethod)(double);
BankAccount CreateBankAccount(double initialBalance)
{
// Initialization
NSCAssert(initialBalance >= 0.0, @"initialBalance must not be negative");
double __block balance = initialBalance;
// "Method Definitions"
CurrentBalanceMethod currentBalance = ^id{
return @(balance);
};
DepositMethod deposit = ^id(double depositAmount)
{
NSCAssert(depositAmount > 0.0, @"depositAmount must be greater than zero");
balance = balance + depositAmount;
return @(balance);
};
WithdrawMethod withdraw = ^id(double withdrawAmount)
{
NSCAssert(withdrawAmount > 0.0, @"withdrawAmount must be greater than zero");
BOOL hasSufficientBalance = (balance >= withdrawAmount);
if (hasSufficientBalance) {
balance = balance - withdrawAmount;
return @(balance);
} else {
return [NSError errorWithDomain:@"BankAccountErrorDomain" code:2 userInfo:@{ NSLocalizedDescriptionKey : @"Insufficient balance" }];
}
};
// Message Dispatch
id bankAccountBlock = ^id(char *cmd)
{
if (strcmp(cmd, "currentBalance") == 0) {
return currentBalance;
} else if (strcmp(cmd, "deposit") == 0) {
return deposit;
} else if (strcmp(cmd, "withdraw") == 0) {
return withdraw;
} else {
return [NSError errorWithDomain:@"BankAccountErrorDomain" code:1 userInfo:@{ NSLocalizedDescriptionKey : @"Unknown command" }];
}
};
return bankAccountBlock;
}
int main(int argc, const char * argv[])
{
@autoreleasepool {
BankAccount account = CreateBankAccount(100);
NSNumber *balance = ((CurrentBalanceMethod)account("currentBalance"))();
NSLog(@"Balance: %@", balance);
balance = ((DepositMethod)account("deposit"))(50);
NSLog(@"Depositing 50, new balance: %@", balance);
balance = ((WithdrawMethod)account("withdraw"))(30);
NSLog(@"Withdrawing 30, new balance: %@", balance);
balance = ((WithdrawMethod)account("withdraw"))(100);
NSLog(@"Withdrawing 100, new balance: %@", balance);
}
return 0;
}
@ole
Copy link
Author

ole commented Feb 11, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment