Slide 1

Slide 1 text

DESIGNING | BUILDING DSLS IN SWIFT @KYLEFULLER

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

BASE

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

SHAPE

Slide 7

Slide 7 text

WHAT IS A DSL?

Slide 8

Slide 8 text

DOMAIN SPECIFIC LANGUAGE

Slide 9

Slide 9 text

PROGRAMMING LANGUAGE

Slide 10

Slide 10 text

DECLARATIVE

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

SPECIFIC

Slide 13

Slide 13 text

NOT GENERIC

Slide 14

Slide 14 text

FREEDOM

Slide 15

Slide 15 text

BUGS

Slide 16

Slide 16 text

NSPredicate

Slide 17

Slide 17 text

NAME EQUALS Kyle

Slide 18

Slide 18 text

USING NSPredicate

Slide 19

Slide 19 text

NSExpression *left = [NSExpression expressionForKeyPath:@"name"]; NSExpression *right = [NSExpression expressionForConstantValue:@"Kyle"]; [NSComparisonPredicate predicateWithLeftExpression:left rightExpression:right modifier:NSDirectPredicateModifier type:NSEqualToPredicateOperatorType options:0];

Slide 20

Slide 20 text

IMPERATIVE

Slide 21

Slide 21 text

FRUSTRATING

Slide 22

Slide 22 text

[NSPredicate predicateWithFormat:@"name == Kyle"];

Slide 23

Slide 23 text

EASY TO WRITE BUGS

Slide 24

Slide 24 text

[NSPredicate predicateWithFormat:@"nme == Kyle"];

Slide 25

Slide 25 text

NSString *key = NSStringFromSelector(@selector(name)); [NSPredicate predicateWithFormat:@"%K == Kyle", key];

Slide 26

Slide 26 text

INELEGANT

Slide 27

Slide 27 text

DSLS

Slide 28

Slide 28 text

[[Person name] equals:@"Kyle"]

Slide 29

Slide 29 text

SWIFT

Slide 30

Slide 30 text

CUSTOM OPERATORS

Slide 31

Slide 31 text

(Something) == (Something else)

Slide 32

Slide 32 text

/ = - + * % < > ! & | ^ . ~

Slide 33

Slide 33 text

Person.name == "Kyle"

Slide 34

Slide 34 text

IDEA

Slide 35

Slide 35 text

CORE DATA DSL

Slide 36

Slide 36 text

MAKING A QUERY IN CORE DATA

Slide 37

Slide 37 text

let fetchRequest = NSFetchRequest(entityName: "Person") fetchRequest.predicate = NSPredicate(format:"name == %@", "Kyle") fetchRequest.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)] var error:NSErrorPointer? var objects = managedObjectContext.executeFetchRequest(fetchRequest, error:error!) if let objects = objects { ; }

Slide 38

Slide 38 text

6 LINES

Slide 39

Slide 39 text

Person.queryset(context) .orderBy(Person.name.ascending) .filter(Person.name == "Kyle")

Slide 40

Slide 40 text

1 LINE

Slide 41

Slide 41 text

REFACTORING

Slide 42

Slide 42 text

class Person : NSManagedObject { var name:String? - var age:NSNumber? }

Slide 43

Slide 43 text

class Person : NSManagedObject { var name:String? - var age:NSNumber? + var birthday:NSDate? }

Slide 44

Slide 44 text

BUILD SUCCESSFUL

Slide 45

Slide 45 text

No content

Slide 46

Slide 46 text

*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath age not found in entity ' *** First throw call stack: ( 0 CoreFoundation 0x00000001039e5495 __exceptionPreprocess + 165 1 libobjc.A.dylib 0x0000000102fe199e objc_exception_throw + 43 2 CoreData 0x0000000100b04438 -[NSSQLGenerator newSQLStatementForFetchRequest:ignoreInheritance:countOnly:nestingLevel:] + 904 3 CoreData 0x0000000100b03f6d -[NSSQLAdapter _newSelectStatementWithFetchRequest:ignoreInheritance:] + 365 4 CoreData 0x0000000100b03bd3 -[NSSQLCore newRowsForFetchPlan:] + 115 5 CoreData 0x0000000100b034a4 -[NSSQLCore objectsForFetchRequest:inContext:] + 516 6 CoreData 0x0000000100b03025 -[NSSQLCore executeRequest:withContext:error:] + 245 7 CoreData 0x0000000100b02b60 -[NSPersistentStoreCoordinator executeRequest:withContext:error:] + 3504 8 CoreData 0x0000000100b00a21 -[NSManagedObjectContext executeFetchRequest:error:] + 497 9 Fitness First 0x000000010021d89a -[KFObjectManager array:] + 138 10 Fitness First 0x00000001000c6396 -[FFGDashboardViewController viewWillAppear:] + 1190 11 UIKit 0x0000000101ae8db5 -[UIViewController _setViewAppearState:isAnimating:] + 422 12 UIKit 0x0000000101d42410 -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:animation:] + 5629 13 UIKit 0x0000000101aeffce -[UIViewController presentViewController:withTransition:completion:] + 4854 ) libc++abi.dylib: terminating with uncaught exception of type NSException

Slide 47

Slide 47 text

Keypath age not found in entity

Slide 48

Slide 48 text

class Person : NSManagedObject { var name:String? - var age:NSNumber? + var birthday:NSDate? }

Slide 49

Slide 49 text

NSSortDescriptor(key: "age", ascending: true)

Slide 50

Slide 50 text

COULD WE DO THIS BETTER WITH A DSL?

Slide 51

Slide 51 text

SAY NO TO HARD CODED STRINGS

Slide 52

Slide 52 text

Person.age.ascending

Slide 53

Slide 53 text

READABILITY

Slide 54

Slide 54 text

SAFE

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

DSLS ARE !

Slide 57

Slide 57 text

!

Slide 58

Slide 58 text

DON'T ABUSE THE POWER Swift HAS GIVEN US.

Slide 59

Slide 59 text

GOING TOO FAR

Slide 60

Slide 60 text

BAD

Slide 61

Slide 61 text

Person.name %= "Kyle"

Slide 62

Slide 62 text

CONSIDERATION

Slide 63

Slide 63 text

INTUITIVE

Slide 64

Slide 64 text

>>> Person.age > 27 Age is more than 27

Slide 65

Slide 65 text

>>> Person.name %= "Kyle" Name is ? Kyle

Slide 66

Slide 66 text

>>> Person.name ~= "Kyle" Name is LIKE Kyle

Slide 67

Slide 67 text

WHERE TO START?

Slide 68

Slide 68 text

README

Slide 69

Slide 69 text

No content

Slide 70

Slide 70 text

README

Slide 71

Slide 71 text

PLAYGROUNDS

Slide 72

Slide 72 text

QuerySet().filter(Person.name == "Kyle") .orderBy(Person.name.ascending)

Slide 73

Slide 73 text

No content

Slide 74

Slide 74 text

class Attribute { var ascending:NSSortDescriptor { return NSSortDescriptor(key: "x", ascending: true) } var descending:NSSortDescriptor { return NSSortDescriptor(key: "x", ascending: true) } } @infix func == (left: Attribute, right: AnyObject) -> NSPredicate { return NSPredicate(format: "x", nil) }

Slide 75

Slide 75 text

class QuerySet { func orderBy(sortDescriptor:NSSortDescriptor) -> QuerySet { return self } func filter(predicate:NSPredicate) -> QuerySet { return self } subscript(range: Range) -> QuerySet { return self } }

Slide 76

Slide 76 text

class Person { class var name:Attribute { return Attribute() } } QuerySet().filter(Person.name == "Kyle") .orderBy(Person.name.ascending)

Slide 77

Slide 77 text

!

Slide 78

Slide 78 text

WHAT'S NEXT?

Slide 79

Slide 79 text

WRITING THE REAL IMPLEMENTATION

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

No content

Slide 82

Slide 82 text

No content

Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

No content

Slide 85

Slide 85 text

No content

Slide 86

Slide 86 text

04:00 AM

Slide 87

Slide 87 text

No content

Slide 88

Slide 88 text

No content

Slide 89

Slide 89 text

No content

Slide 90

Slide 90 text

No content

Slide 91

Slide 91 text

github.com/kylef/QueryKit

Slide 92

Slide 92 text

twitter.com/kylefuller

Slide 93

Slide 93 text

No content

Slide 94

Slide 94 text

github.com/kylef/QueryKit twitter.com/kylefuller