Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Techniques to write DSLs in Swift
Search
Luis Solano
June 06, 2014
Programming
1.5k
7
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Techniques to write DSLs in Swift
Luis Solano
June 06, 2014
More Decks by Luis Solano
See All by Luis Solano
How I Spent All My Savings Reinventing Programming
luisobo
0
280
Consuming Web APIs, the TDD way
luisobo
6
380
Techniques to write DSLs in Objective-C
luisobo
9
930
Other Decks in Programming
See All in Programming
Even G2とAWSで推しのエージェントを召喚しよう!
har1101
1
160
symfony/aiとlaravel/boost
77web
0
120
ローカルLLMでどこまでコードが書けるか -拡張版 / How much code can be written on a local LLM Extended
kishida
12
4.7k
The Bowling Game- From Imperative to Functional Programming - Part 1
philipschwarz
PRO
0
310
なぜ型を書くのか? TSKaigi2026で改めて考える #tskaigi_smarthr
kajitack
0
340
トークンをケチるな、設計しろ:GitHub Copilotを賢く使うコンテキスト戦略
ochtum
0
310
LLMによるContent Moderationの本番運用の裏側と品質担保への挑戦
suikabar
3
840
エンジニア向け会社紹介/Findy Company Profile
findyinc
6
360k
OS アップデート対応の取り組み方がもっと共有されてほしい
andpad
0
110
霧の中の代数的エフェクト
funnyycat
1
340
アルゴリズムは何を圧縮しているのか ─ Haskell から育った「圧縮代数」というメンタルモデル
naoya
16
3.3k
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.8k
Featured
See All Featured
The browser strikes back
jonoalderson
0
1.4k
BBQ
matthewcrist
89
10k
Balancing Empowerment & Direction
lara
6
1.2k
Leveraging Curiosity to Care for An Aging Population
cassininazir
1
350
Mind Mapping
helmedeiros
PRO
1
280
How to Align SEO within the Product Triangle To Get Buy-In & Support - #RIMC
aleyda
2
1.6k
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
360
Become a Pro
speakerdeck
PRO
31
6k
The Cost Of JavaScript in 2023
addyosmani
55
10k
The Director’s Chair: Orchestrating AI for Truly Effective Learning
tmiket
1
210
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.4k
Intergalactic Javascript Robots from Outer Space
tanoku
273
27k
Transcript
“Clean code reads like well-written prose” – Grady Booch
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 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
@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
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
TECHNIQUES TO WRITE DSLs IN OBJECTIVE-C
TECHNIQUES TO WRITE DSLs IN SWIFT
LUIS SOLANO @luisobo
DOMAIN-SPECIFIC LANGUAGE
LANGUAGE PROGRAMMING
SPECIFIC CONSTRAINT
TO A CERTAIN DOMAIN CERTAIN TYPE OF PROBLEM
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
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
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
sm.when("activate", transitionFrom: "pending", to: "active") DSL
DSL luisobo/StateMachine
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") { subscription in subscription.terminatedAt = NSDate.date() } ! sm.before("suspend") { subscription in subscription.stopBilling() } DSL
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
asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla asjdañlksjdlaksjdñlak asjdañlksjdla Semantic model
Domain-specfic language
DECLARATIVE
imperative
imperative is fine
imperative works
my brain
my brain cannot handle imperative programming’s scale
DECLARATIVE
INTERNAL EXTERNAL INTERNAL
DSL? WHY TO
DSL? WHEN TO
DSL? HOW TO
SWIFT METHODS luisobo/StateMachine sm.when("activate", transitionFrom: "pending", to: "active")
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]; SWIFT METHODS luisobo/StateMachine
SWIFT METHODS luisobo/StateMachine sm.when("activate", transitionFrom: "pending", to: "active")
METHOD CHAINING stubRequest("GET", "http://hello.com/"). andReturn(200).withBody("hola"); luisobo/Nocilla
stubRequest("POST", "http://hello.com"). withHeader("Content-Type", "text/plain"). withHeader("X-MY-AWESOME-HEADER", "sisisi"). withBody("Adios!"). andReturn(200). withHeader("Content-Type", "text/plain").
withBody("hola"); METHOD CHAINING luisobo/Nocilla
EXTENSIONS state.should.eq(“active”)
EXTENSIONS extension NSObject { var should:Matcher { return Matcher() }
}
[1, 2, 3] [1: “one”, 2: “two”, 3: “three”] ARRAY
AND DICTIONARY LITERALS
stubRequest("GET", “http://hello.com"). withHeaders([“Content-Type": “text/plain", "X-MY-AWESOME-HEADER" : “YEAH!”]). andReturn(200); luisobo/Nocilla ARRAY
AND DICTIONARY LITERALS
.adjustTemperature(24.5).at(“nine"). USING LITERALS WITH YOUR TYPES
func adjustTemperature(to: Temp) -> Thermostat func at(time: NSDate) -> Thermostat
USING LITERALS WITH YOUR TYPES
protocol FloatLiteralConvertible { ! typealias FloatLiteralType ! class func convertFromFloatLiteral(value:
FloatLiteralType) -> Self ! } USING LITERALS WITH YOUR TYPES
extension Temp: FloatLiteralConvertible { typealias FloatLiteralType = Double class func
convertFromFloatLiteral(value: Double) -> Temp { return Temp(degrees: value) } } USING LITERALS WITH YOUR TYPES
IntegerLiteralConvertible FloatLiteralConvertible StringLiteralConvertible LogicValue StringInterpolationConvertible ArrayLiteralConvertible DictionaryLiteralConvertible USING LITERALS WITH
YOUR TYPES 1 3.5 “foo” if myValue “hello \(value)” [1, 2, 3] [“one”: 1, “two”: 2]
BLOCKS sm.before("terminate") { subscription in subscription.terminatedAt = NSDate.date() } luisobo/StateMachine
BLOCKS FOR CONTEXT User.defineFactory { f in f["foo"] = "bar"
f["password"] = "hunter2" } luisobo/Defactory
SYNTACTIC SUGAR o.com”).with.body(“Hola”).and.return(200) luisobo/Nocilla
OPERATOR OVERLOAD ^= *= * % + - / <<=
||= << || |= <= >>= !== >= ~= | >> < += &&= %= ... -= &% /= && &* &+ &- &/ === == & .. ^ > &= != ~ ! -- ++ - + -- ++
OPERATOR OVERLOAD let s: Speed = 100.meters / 5.seconds
CUSTOM OPERATORS / = - + * % < >
! & | ^ . ~.
CUSTOM OPERATORS operator infix =>> {}
=>>
stubRequest("GET","http://hello.com/") luisobo/Nocilla stubRequest(method:String, url:String)
stubRequest("GET", "http://hello.com/") stubRequest(“GET", regex(“http://.*\.com”)) luisobo/Nocilla stubRequest(method:String, url:AnyObject)
stubRequest("POST", NSObject()); stubRequest(“POST”, []); luisobo/Nocilla stubRequest(method:String, url:AnyObject)
protocol Matchable { func matcher() -> Matcher } ADD PROTOCOL
TO EXISTING CLASS luisobo/Nocilla
extension NSString: Matchable { func matcher() -> Matcher { return
StringMatcher(pattern: self) } } ADD PROTOCOL TO EXISTING CLASS
ADD PROTOCOL TO EXISTING CLASS extension NSRegularExpression: Matchable { func
matcher() -> Matcher { return RegexMatcher(pattern: self) } }
ADD PROTOCOL TO EXISTING CLASS stubRequest("GET", "http://hello.com/") stubRequest(“GET", regex(“http://.*\.com”)) luisobo/Nocilla
stubRequest(method:String, url:Matcheable)
stubRequest("POST", NSObject()]); stubRequest(“POST”,[]]); stubRequest(method:String, url:Matcheable) ADD PROTOCOL TO EXISTING CLASS
luisobo/Nocilla
None
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
! ! 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