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
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
2k
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
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
170
数年滞っていたダークモード対応をおよそ2週間で完了させる
chigichan24
0
730
PL/pgSQLはなぜ「ふつうのSQL」より遅いのか
tameguro
0
110
Jetpack Compose メカニズム
skydoves
0
440
GKE で Pod の見方を変えたら、スケールアウト時の挙動を真に捉えられた話
stkk
0
130
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
150
大喜利で理解するLLM as a Judge / Understanding LLM-as-a-Judge through Ogiri
rockname
0
140
AI が書く Go コードの品質を劇的に向上させる Linter: “declscope”
mpyw
0
370
AIは賢い。でも実行環境は? CLIおじさんがAI時代に伝えたいこと ~ CLIおじさんがAI時代に伝えたいこと ~
curekoshimizu
1
250
SREの越境 / SRE Collaboration
y0hgi
2
240
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
200
更なる可用性を求めて、5年間運用したKotlinのアプリケーションをGoでリプレイスする話
ken_tunc
0
290
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
21
3.8k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.6k
4 Signs Your Business is Dying
shpigford
187
23k
KATA
mclloyd
PRO
35
15k
Six Lessons from altMBA
skipperchong
29
4.5k
The browser strikes back
jonoalderson
0
1.7k
We Have a Design System, Now What?
morganepeng
55
8.3k
Color Theory Basics | Prateek | Gurzu
gurzu
1
470
GraphQLの誤解/rethinking-graphql
sonatard
75
12k
A Soul's Torment
seathinner
8
3.6k
Designing for Timeless Needs
cassininazir
1
480
Darren the Foodie - Storyboard
khoart
PRO
4
3.9k
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)