$30 off During Our Annual Pro Sale. View Details »

Techniques to write DSLs in Objective-C

Techniques to write DSLs in Objective-C

"Clean code reads like well-written prose" - Grady Booch

Programming languages can be a really powerful tool, so powerful they allow
us to make mistakes and introduce bugs in our programs. So powerful they
allow us to poorly design or programs, making them hard to modify or extend.

A domain-specific language is a small language that allows us to solve
problems in a particular domain and because they are both constrained and
declarative there is almost no room for mistakes. DSLs make our code much
easier to read, maintain and modify.

This talk will cover:
* The main advantages and disadvantages of using DSLs
* When to use them
* How to raise the level of abstraction and separate implementation details
from expected behavior
* What are the main techniques to write DSLs in Objective-C.

Luis Solano

May 15, 2014
Tweet

More Decks by Luis Solano

Other Decks in Programming

Transcript

  1. asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla

    asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla
  2. @implementation Subscription - (id)init { self = [super init]; if

    (!self) return nil; self.state = @"pending"; } - (void)activateWithCode:(NSString *)activationCode { if ([self.state isEqualToString:@"pending"] && [self.code isEqualToString:activationCode]) { self.state = @"active"; } } - (void)suspend { if ([self.state isEqualToString:@"active"]) { [self stopBilling]; } } @end IMPLEMENTATION
  3. LSStateMachine *sm = [[LSStateMachine alloc] init]; LSState *s1 = [[LSState

    alloc] initWithName:@"pending"]; LSState *s2 = [[LSState alloc] initWithName:@"active"]; [sm addState:s1]; [sm addState:s2]; LSEvent *e1 = [[LSEvent alloc] initWithName:@"activate"]; LSTransition *t1 = [[LSTransition alloc] initWithEvent:e1 from:s1 to:s2]; [sm addTransition:t1]; ABSTRACTION
  4. LSStateMachine *sm = [[LSStateMachine alloc] init]; LSState *s1 = [[LSState

    alloc] initWithName:@"pending"]; LSState *s2 = [[LSState alloc] initWithName:@"active"]; [sm addState:s1]; [sm addState:s2]; LSEvent *e1 = [[LSEvent alloc] initWithName:@"activate"]; LSTransition *t1 = [[LSTransition alloc] initWithEvent:e1 from:s1 to:s2]; [sm addTransition:t1]; ABSTRACTION
  5. asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla

    asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla
  6. LSStateMachine *sm = [[LSStateMachine alloc] init]; LSState *s1 = [[LSState

    alloc] initWithName:@"pending"]; LSState *s2 = [[LSState alloc] initWithName:@"active"]; [sm addState:s1]; [sm addState:s2]; LSEvent *e1 = [[LSEvent alloc] initWithName:@"activate"]; LSTransition *t1 = [[LSTransition alloc] initWithEvent:e1 from:s1 to:s2]; [sm addTransition:t1]; ABSTRACTION
  7. STATE_MACHINE(^(LSStateMachine *sm) { sm.initialState = @"pending"; ! [sm when:@"activate" transitionFrom:@"pending"

    to:@"active"]; [sm when:@"suspend" transitionFrom:@"active" to:@"suspended"]; [sm when:@"unsuspend" transitionFrom:@"suspended" to:@"active"]; [sm when:@"terminate" transitionFrom:@"active" to:@"terminated"]; [sm when:@"terminate" transitionFrom:@"suspended" to:@"terminated"]; [sm before:@"terminate" do:^(Subscription *subscription){ subscription.terminatedAt = [NSDate date]; }]; [sm after:@"suspend" do:^(Subscription *subscription) { [subscription stopBilling]; }]; }); DSL
  8. asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla

    asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla
  9. LSStateMachine *sm = [[LSStateMachine alloc] init]; LSState *s1 = [[LSState

    alloc] initWithName:@"pending"]; LSState *s2 = [[LSState alloc] initWithName:@"active"]; [sm addState:s1]; [sm addState:s2]; LSEvent *e1 = [[LSEvent alloc] initWithName:@"activate"]; LSTransition *t1 = [[LSTransition alloc] initWithEvent:e1 from:s1 to:s2]; [sm addTransition:t1]; OBJECTIVE-C METHODS luisobo/StateMachine
  10. DSL ENTRY POINT #define _CONCAT(a,b) a##b #define _LABEL(a) _CONCAT(MyFunction, a)

    #define _UNIQUE_NAME _LABEL(__COUNTER__) luisobo/Defactory
  11. BLOCKS FOR CONTEXT STATE_MACHINE(^(LSStateMachine *sm) { sm.initialState = @"pending"; !

    [sm when:@"activate" transitionFrom:@"pending" to:@"active"]; ! // ... }); luisobo/StateMachine
  12. SCOPES @implementation SomeClass ! ! ! ! ! ! @end

    LAZY(formatter, { NSDateFormatter *f = [NSDateFormatter new]; [f setDateFormat:@"%Y-%m-%d %H:%M:%S"]; f; });
  13. @interface NSString (Matcheable) <LSMatcheable> ! @end ! @implementation NSString (Matcheable)

    ! - (LSMatcher *)matcher { return [[LSStringMatcher alloc] initWithString:self]; } ! @end ! ADD PROTOCOL TO EXISTING CLASS
  14. @interface NSRegularExpression (Matcheable) <LSMatcheable> ! @end ! @implementation NSRegularExpression (Matcheable)

    ! - (LSMatcher *)matcher { return [[LSRegexMatcher alloc] initWithRegex:self]; } ! @end ! ADD PROTOCOL TO EXISTING CLASS
  15. stubRequest(NSString *method, id<LSMatcheable> url) ADD PROTOCOL TO EXISTING CLASS stubRequest(@"GET",

    @"http://hello.com/") stubRequest(@“GET", regex(@“http://.*\.com”)) luisobo/Nocilla
  16. Thin layer on top of an abstraction. Limited expressiveness and

    domain focus. Make your code more maintainable Developer happiness Improved communication Fewer bugs! As seen in TV
  17. ! ! Domain-specific languages by Martin Fowler brain photo: flickr/_DJ_

    redacted font: github/christiannaths Nocilla: github/luisobo StateMachine: github/luisobo Defactory: github/luisobo Kiwi: github/kiwi-bdd metamacros.h github/jspahrsummers THANKS! @luisobo