Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Brandon Kase: Grokking Lazy Sequences and Colle...
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
Realm
July 07, 2016
Programming
9k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Brandon Kase: Grokking Lazy Sequences and Collections
Realm
July 07, 2016
More Decks by Realm
See All by Realm
WWDC 2017 Review
realm
0
2.2k
Xcode shortcuts
realm
0
4.8k
Self Branding with GitHub
realm
0
4.4k
Realm Mobile Platform overview and demo
realm
0
2.1k
Realm advanced topics and demo
realm
0
2.1k
Realm introduction Seoul meetup 10
realm
0
2.2k
Stuart Hall: How I got 2.3 Million App Downloads
realm
0
2k
James Majors: What the Swiftly Func?
realm
1
4.3k
Simina Pasat: Continuous everything for iOS apps
realm
0
670
Other Decks in Programming
See All in Programming
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
370
phperだってパンチカードでコーディングしたい
o0h
PRO
0
280
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
4
4.6k
Jetpack Compose Mechanisms
skydoves
2
710
複雑なUIコンポーネントとの ⻑い付き合い⽅:波及するバグからテスト戦略を経て、安全な再設計へ
mixplace
0
380
プロダクトコードからライブラリの境界を見つける
elmetal
PRO
0
110
golang-bob.pdf
iwatsukayura
0
120
JAWS-UG 東京支部が始める、JAWS-UG支部コラボ / JAWS-UG lunchtime LT Collaboration
y0hgi
0
230
ハーネス設計入門 〜 基礎知識の整理から実務へのステップアップ 〜
kinopeee
22
22k
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
1
2.3k
R8 の設定見直しでアプリサイズ削減
andpad
0
210
The Rails Doctrine Decade
koic
2
560
Featured
See All Featured
Deep Space Network (abreviated)
tonyrice
0
360
svc-hook: hooking system calls on ARM64 by binary rewriting
retrage
2
620
Git: the NoSQL Database
bkeepers
PRO
433
67k
Paper Plane
katiecoart
PRO
4
54k
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
620
The Web Performance Landscape in 2024 [PerfNow 2024]
tammyeverts
12
1.3k
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
280
Optimizing for Happiness
mojombo
378
71k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
Building AI with AI
inesmontani
PRO
1
1.3k
SEO for Brand Visibility & Recognition
aleyda
0
4.8k
Being A Developer After 40
akosma
92
590k
Transcript
GROKKING LAZY SEQUENCES AND COLLECTIONS By / Brandon Kase @bkase_
PHOTOS http://friendlycomputersspokane.com/wp-content/uploads/2014/06/photo-stack.jpg
PHOTOS
PROBLEMS There are a lot of photos Loading a photo's
data is expensive
PROBLEMS There are a lot of things Loading a thing
is expensive
HOLDING THINGS http://odditymall.com/includes/content/wall-mounted-hands-for-holding-stuff-0.jpg
HOLDING THINGS Arrays?
HOLDING THINGS let fetchresult = PHAsset.fetchAllAssets/*...*/()
HOLDING THINGS let fetchresult = PHAsset.fetchAllAssets/*...*/() var arr = [PHAsset]()
HOLDING THINGS let fetchresult = PHAsset.fetchAllAssets/*...*/() var arr = [PHAsset]()
fetchresult.enumerateAssetsUsingBlock { obj, /*...*/ arr.append(obj as! PHAsset) }
HOLDING THINGS let fetchresult = PHAsset.fetchAllAssets/*...*/() var arr = [PHAsset]()
fetchresult.enumerateAssetsUsingBlock { obj, /*...*/ arr.append(obj as! PHAsset) } // slowwwwww
HOLDING THINGS We need a Collection
GROUPS OF THINGS A Collection is an Indexable Sequence A
Sequence is an Iterator maker An Iterator can produce one or more Elements
ITERATORPROTOCOL protocol IteratorProtocol { associatedtype Element mutating func next() ->
Element? }
ITERATORPROTOCOL Let's say we want to iterate over the even
numbers https://i.ytimg.com/vi/A9NfHIIwNN4/maxresdefault.jpg
ITERATORPROTOCOL struct Evens: IteratorProtocol { var state: Int = 0
mutating func next() -> Int? { let curr = state state += 2 return .some(curr) } }
ITERATORPROTOCOL let s = Evens() for _ in 1...5 {
print(s.next()!) // 0, 2, 4, 6, 8 }
SEQUENCE Recall: A Sequence is an Iterator maker http://ichef.bbci.co.uk/news/660/media/images/80295000/jpg/_80295405_thinking522738989.jpg
ITERATORPROTOCOL struct Evens: IteratorProtocol, Sequence
SEQUENCE for x in Evens().prefix(5) { print(x) // 0, 2,
4, 6, 8 }
SEQUENCE http://customer-blog-images.s3.amazonaws.com/questions.jpg
SEQUENCE extension Sequence where Iterator == Self, Self: IteratorProtocol {
func makeIterator() -> Iterator { return self } }
SEQUENCE http://www.thedirtondusters.com/wp-content/uploads/2012/08/WHAT-ELSE-NO-TEXT.jpg
SEQUENCE for x in someSequence { print(x) }
SEQUENCE map, filter, reduce prefix, dropFirst much, much more
SEQUENCE must be able to produce an iterator could be
one-pass or multipass could be finite or infinite
COLLECTION http://ichef.bbci.co.uk/news/660/media/images/80295000/jpg/_80295405_thinking522738989.jpg
COLLECTION protocol Collection: Sequence, Indexable
COLLECTION http://friendlycomputersspokane.com/wp-content/uploads/2014/06/photo-stack.jpg
COLLECTION struct PhotosMetadata: Collection { /*...*/ var startIndex: Int {
/*...*/ } var endIndex: Int { /*...*/ } func index(after i: Int) -> Int { /*...*/ } subscript(i: Int) -> PHAsset { /*...*/ } }
COLLECTION Why do we need to deal with the index
crap? struct PhotosMetadata: Collection { /*...*/ var startIndex: Int { /*...*/ } var endIndex: Int { /*...*/ } func index(after i: Int) -> Int { /*...*/ } subscript(i: Int) -> PHAsset { /*...*/ } }
COLLECTION RULES has addressable positions (index) must support multipass iteration
exists a one-to-one mapping of indices to elements No infinite structures! expect O(1) subscript access
COLLECTION Non-integer indices are useful: https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/CPT-LinkedLists-deletingnode.svg/380px-CPT- LinkedLists-deletingnode.svg.png
COLLECTION struct PhotosMetadata: Collection {
COLLECTION private let base: PHFetchResult init(_ base: PHFetchResult) { self.base
= base }
COLLECTION var startIndex: Int { return 0 }
COLLECTION var endIndex: Int { return base.count }
COLLECTION func index(after i: Int) -> Int { return i
+ 1 }
COLLECTION subscript(i: Int) -> PHAsset { return base[i] as! PHAsset
}
PHOTOS let a = PhotosMetadata(PHAsset.fetchAllAssets/*...*/()) // not slow!
PHOTOS Now we want to turn our PHAssets into Photos
PHOTOS struct Photo { let url: NSURL /*...*/ }
PHOTOS let metadata: PhotosMetadata let photos = metadata.map{ Photo(url: $0.url)
} // slowwww
PHOTOS Delay metadata load
PHOTOS Delay operations on collections or sequences
LAZY GROUPS OF THINGS Transformations computed when the information is
forced out https://media.giphy.com/media/AyXMnDH4nA7jW/giphy.gif
LAZYSEQUENCE protocol LazySequenceProtocol: Sequence
LAZYCOLLECTION protocol LazyCollectionProtocol: LazySequenceProtocol, Collection
NORMAL MAP // eager sequence/collection [1,2,3].map{ $0 + 1 }
// [2, 3, 4]
LAZYSEQUENCE MAP Evens().lazy.map{ $0 + 1 } // LazyMapSequence<Int, Int>
// nothing is computed yet!
LAZYCOLLECTION MAP [1,2,3].lazy.map{ $0 + 1 } // LazyMapRandomAccessCollection<Int, Int>
// nothing is computed yet!
WAIT A SECOND protocol LazyCollectionProtocol: LazySequenceProtocol, Collection
H O W C A N A N O V
E R R I D E N M E T H O D R E T U R N D I F F E R E N T T Y P E S ?
PROTOCOL DEFAULT IMPLEMENTATIONS https://pptcrafter.files.wordpress.com/2013/01/gears-0.png
DEFAULT IMPLEMENTATIONS protocol A { } extension A { func
woo() -> Self { return self } func hi() -> String { return "A" } }
DEFAULT IMPLEMENTATIONS struct ConcA: A {} print(ConcA().woo().hi()) // "A"
DEFAULT IMPLEMENTATIONS protocol B { } extension B { func
hi() -> Int { return 0 } }
DEFAULT IMPLEMENTATIONS struct Mystery: A, B { } print(Mystery().woo().hi()) //
compile error!
DEFAULT IMPLEMENTATIONS // now B subsumes A protocol B: A
{ } extension B { func hi() -> Int { return 0 } }
DEFAULT IMPLEMENTATIONS struct Mystery: B { } print(Mystery().woo().hi()) // 0
// NOT a compile error!
MAPS Evens().lazy.map{ $0 + 1 } // LazyMapSequence<Int, Int> //
nothing is computed yet!
LAZYMAPSEQUENCE? struct LazyMapSequence<S: Sequence>: LazySequenceProtocol
LAZYMAPSEQUENCE struct LazyMapSequence<S: Sequence>: LazySequenceProtocol { func makeIterator() -> LazyMapIterator</*...*/>
{ /*...*/ } }
LAZYMAPITERATOR struct LazyMapIterator<Base: Iterator, Element>: IteratorProtocol, Sequence { }
LAZYMAPITERATOR struct LazyMapIterator<Base: Iterator, Element>: IteratorProtocol, Sequence { var _base:
Base let _transform: (Base.Element) -> Element }
LAZYMAPITERATOR struct LazyMapIterator<Base: Iterator, Element>: IteratorProtocol, Sequence { var _base:
Base let _transform: (Base.Element) -> Element mutating func next() -> Element? { return _base.next().map(_transform) } }
LAZYMAPSEQUENCE struct LazyMapSequence<S: Sequence>: LazySequenceProtocol http://www.tacobueno.com/media/1381/beefbob.png?quality=65
BURRITOS let a = [1,2,3].lazy.map{ $0 + 1 }.filter{ $0
!= 3 } // a: LazyFilterBidirectionalCollection< // LazyMapRandomAccessCollection< // Array<Int>, Int // > // >
BURRITOS http://images.wisegeek.com/flour-tortilla.jpg
PHOTOS let metadata: PhotosMetadata let photos = metadata.lazy.map{ Photo(url: $0.url)
} // not slow!
PHOTOS func prepareData(d: PhotosMetadata) -> ? { return d.lazy .filter{
$0.isPhoto() } // skip videos .map{ Photo(url: $0.url) } // make photos .map{ PhotoView(photo: $0) } // make view }
PHOTOS LazyFilterBidirectionalCollection< LazyMapRandomAccessCollection< LazyMapRandomAccessCollection< PHAsset, Photo >, PhotoView > >
TORTILLA INFERENCE http://m.jumpstart.com/JumpstartNew/uploadedFiles/sne/small-screenshots/the-magic-tortilla.jpg
TYPE INFERENCE let m = d.lazy.map/*...*/ return m.first
TORTILLA ERASURE https://2e0a24317f4a9294563f-26c3b154822345d9dde0204930c49e9c.ssl.cf1.rackcdn.com/9218426_the-tortilla- pencil-case-deliciously-wraps_11d463da_m.jpg?bg=DFC1B7
TYPE ERASURE let m = AnyCollection( d.lazy.filter{}.map{}/*...*/ ) // m:
AnyCollection<PhotoView>
TYPE ERASURE AnySequence AnyCollection ... see appendix for more
PHOTOS func prepareData(d: PhotosMetadata) -> AnyCollection<PhotoView>
PHOTOS Product wants everyOther photo http://www.giftofcuriosity.com/wp-content/uploads/2016/04/Letter-hopscotch-4.jpg
NEW TORTILLAS let a = [1,2,3,4] for x in a.lazy.everyOther()
{ print(x) // 2,4 }
NEW TORTILLAS // the tortilla sequence struct LazyEveryOtherSequence <S: Sequence>:
LazySequenceProtocol { var base: S func makeIterator() -> LazyEveryOtherIterator<S.Iterator> { return LazyEveryOtherIterator(base: base.makeIterator()) } }
NEW TORTILLAS struct LazyEveryOtherIterator <I: IteratorProtocol>: IteratorProtocol { var base:
I mutating func next() -> I.Element? { if let _ = base.next() { return base.next() } else { return nil } } }
NEW TORTILLAS extension LazySequenceProtocol { func everyOther() -> LazyEveryOtherSequence<Self> {
return LazyEveryOtherSequence(base: self) } }
PHOTOS let skipped = photos.everyOther()
PHOTOS Product wants every 4th photo http://www.giftofcuriosity.com/wp-content/uploads/2016/04/Letter-hopscotch-4.jpg
PHOTOS let skipped = photos.everyOther().everyOther()
RECAP
RECAP Collections hold our photo metadata and photos
RECAP Collections hold our photo metadata and photos LazyCollection's map
transforms our data
RECAP Collections hold our photo metadata and photos LazyCollection's map
transforms our data AnyCollection gives maintainable type signatures
RECAP Collections hold our photo metadata and photos LazyCollection's map
transforms our data AnyCollection gives maintainable type signatures We can create new operators that compose
FINALLY Our app works!
P.S. IBM Swift Sandbox is legit Check out Unary indexed
collections in appendix
GROK IT? By / Slide Deck: Brandon Kase @bkase_ https://is.gd/mEvKbt
APPENDIX
EAGER Eager (or strict) is the opposite of lazy Computed
always
EAGER class A { var eagerField: Int = 1 +
1 /* ... */ }
LAZY class A { lazy var lazyField: Int = 1
+ 1 /* ... */ }
EAGER GROUPS OF THINGS
EAGER GROUPS OF THINGS Eager means operations on the groups
of things are eager The groups of things themselves can be strict or lazy
UNARY
UNARY let u: Unary</*...*/> u[""] // 1st element u["x"] //
2st element u["xx"] // 3st element u["xxx"] // 4st element
UNARY Given any input collection addressable via Ints, Create a
collection addressable via unary numbers!
UNARY More powerful than overriding the subscript operator!
UNARY print(u.lazy.map{ x in x + 1 }["xxx"])
UNARY Let's build it
UNARY struct Unary<C: Collection>: Collection where C.Index == Int, C.IndexDistance
== Int {
UNARY { var startIndex: String { /*...*/ } var endIndex:
String { /*...*/ } func index(after i: String) -> String { /*...*/ } subscript(i: String) -> C.Iterator.Element { /*...*/ } }
UNARY private let xs: C init(_ xs: C) { self.xs
= xs }
UNARY var startIndex: String { return "" }
UNARY /// O(n) endIndex var endIndex: String { return String((0...xs.count).map{
_ in "x"}) }
UNARY func index(after i: String) -> String { return i
+ "x" }
UNARY subscript(i: String) -> C.Iterator.Element { return xs[i.characters.count] }
UNARY let u: Unary<Array<Int>> = Unary([1, 2, 3, 4, 5,
6]) print(u.lazy.map{ x in x + 1 }["xxx"])
COLLECTION-INDEX VARIANTS How can you move to the next index?
Collection (ForwardDirection) Go forward in O(1) BidirectionalCollection Go forward or backward in O(1) RandomAccessCollection Get the difference between two indices in O(1)
TYPE ERASURE
TYPE ERASURE Type erasure works by moving the type info
to the constructor
TYPE ERASURE // one of the inits for AnySequence init<S
: Sequence where S.Iterator.Element == Element, S.SubSequence : Sequence, S.SubSequence.Iterator.Element == Element, S.SubSequence.SubSequence == S.SubSequence>(_ base: S)