Skip to content

Instantly share code, notes, and snippets.

@CraigSiemens
Forked from jspahrsummers/iflet.m
Last active May 2, 2021 02:09
Show Gist options
  • Star 13 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save CraigSiemens/bcdefff3880c508ad2b1 to your computer and use it in GitHub Desktop.
Save CraigSiemens/bcdefff3880c508ad2b1 to your computer and use it in GitHub Desktop.
if-let and guard macros for Objective C
#import <Foundation/Foundation.h>
// VARIABLE must be a variable declaration (NSString *foo)
// VALUE is what you are checking is not nil
// WHERE is an additional BOOL condition
#define iflet(VARIABLE, VALUE) \
ifletwhere(VARIABLE, VALUE, YES)
#define ifletwhere(VARIABLE, VALUE, WHERE) \
for (BOOL b_ = YES; b_ != NO;) \
for (id obj_ = (VALUE); b_ != NO;) \
for (VARIABLE = (obj_ ?: (VALUE)); b_ != NO; b_ = NO) \
if (obj_ != nil && (WHERE))
// Called just like the swift verstion
// guard(1 < 2) else {
// return
// }
#define guard(CONDITION) \
if (CONDITION) {}
#define guardletwhere(VARIABLE, VALUE, WHERE) \
ifletwhere(VARIABLE, VALUE, WHERE) {}
int main(int argc, char *argv[]) {
@autoreleasepool {
NSString *x = @"asdf";
NSString *y = nil;
iflet(NSString *z, x) {
NSLog(@"x is not nil");
}
iflet(NSString *z, y) {
NSLog(@"y is not nil");
}
else {
NSLog(@"y is nil");
}
ifletwhere(NSString *z, x, z.length < 100) {
NSLog(@"x is not nil and < 100");
}
guard(3 < 2) else {
NSLog(@"guard failed");
}
guardletwhere(NSString *z, x, z.length < 3) else {
NSLog(@"guardletwhere failed");
}
}
}
/* outputs:
iflet[57328:5182484] x is not nil
iflet[57328:5182484] y is nil
iflet[57328:5182484] x is not nil and < 100
iflet[57328:5182484] guard failed
iflet[57328:5182484] guardletwhere failed
*/
@BananZG
Copy link

BananZG commented Feb 25, 2020

There is an issue when calling 'continue' in these macros, as they are in for loop without brackets

@BananZG
Copy link

BananZG commented Feb 25, 2020

suggesting change to

#define guardletwhere(VARIABLE, VALUE, WHERE) \
    VARIABLE = (VALUE); \
    if (VALUE != nil && (WHERE)) {}
  1. to support continue in if let's else
  2. to keep VARIABLE in the code, same behavior with Swift

@CodingMarkus
Copy link

There is an issue when calling 'continue' in these macros, as they are in for loop without brackets

What difference would it make if they were in a loop with brackets? I see no difference in behavior.

suggesting change to

Yet this approach has two other drawbacks:

  1. VARIABLE will be available outside of the iflet block, which does not match if let behavior in Swift. Also you cannot use the same variable for two iflet blocks in a row as the compiler will throw a re-declaration error but this is also possible in Swift.
  2. You cannot use iflet as an else statement (else iflet (...)) or after another if (if (...) iflet(...)). Both will not create a compile error but the code won't do what you expect it to do.

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