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
Error Handling Without Exceptions
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Ben Darfler
May 06, 2015
Programming
0
140
Error Handling Without Exceptions
A quick jaunt through functional error handling patterns using Ruby
Ben Darfler
May 06, 2015
Tweet
Share
More Decks by Ben Darfler
See All by Ben Darfler
Self-healing Software
bdarfler
0
150
Microservice Architectures
bdarfler
0
94
dotfiles
bdarfler
0
110
Remote Work
bdarfler
0
210
Low Latency Systems: How do they do it?
bdarfler
0
78
Scala
bdarfler
0
140
HTTP/2
bdarfler
0
140
Rails Asset Pipeline and You
bdarfler
0
81
How to Win at the Internet
bdarfler
1
42
Other Decks in Programming
See All in Programming
AI Agent の開発と運用を支える Durable Execution #AgentsInProd
izumin5210
7
2.3k
CSC307 Lecture 01
javiergs
PRO
0
690
Apache Iceberg V3 and migration to V3
tomtanaka
0
150
OSSとなったswift-buildで Xcodeのビルドを差し替えられるため 自分でXcodeを直せる時代になっている ダイアモンド問題編
yimajo
3
610
16年目のピクシブ百科事典を支える最新の技術基盤 / The Modern Tech Stack Powering Pixiv Encyclopedia in its 16th Year
ahuglajbclajep
5
990
ぼくの開発環境2026
yuzneri
0
140
AI Agent Tool のためのバックエンドアーキテクチャを考える #encraft
izumin5210
6
1.8k
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
510
CSC307 Lecture 03
javiergs
PRO
1
490
組織で育むオブザーバビリティ
ryota_hnk
0
170
副作用をどこに置くか問題:オブジェクト指向で整理する設計判断ツリー
koxya
1
600
Oxlint JS plugins
kazupon
1
810
Featured
See All Featured
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
0
430
Color Theory Basics | Prateek | Gurzu
gurzu
0
190
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
122
21k
エンジニアに許された特別な時間の終わり
watany
106
230k
Product Roadmaps are Hard
iamctodd
PRO
55
12k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
350
DevOps and Value Stream Thinking: Enabling flow, efficiency and business value
helenjbeal
1
90
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
1.8k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
35
3.3k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.1k
Deep Space Network (abreviated)
tonyrice
0
47
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
1
49
Transcript
Error Handling Without Exceptions
A Guiding Example ['1','2','3'].map{ |x| Integer(x) }.reduce(:+)
A Guiding Example ['1','2','3'].map{ |x| Integer(x) }.reduce(:+) => 6
A Guiding Example ['1','2','3'].map{ |x| Integer(x) }.reduce(:+) => 6 ['1','2','3','zero'].map{
|x| Integer(x) }.reduce(:+)
A Guiding Example ['1','2','3'].map{ |x| Integer(x) }.reduce(:+) => 6 ['1','2','3','zero'].map{
|x| Integer(x) }.reduce(:+) ArgumentError: invalid value for Integer(): "zero"
“ Errors aren’t exceptions because they’re not exceptional - they’re
real possible outcomes with their own information - treat them as such - Some Guy I Know
Can We Do Better?
Can We Do Better? def safe_to_i(value) Integer(value) rescue nil end
Can We Do Better? def safe_to_i(value) Integer(value) rescue nil end
['1','2','3','zero'].map{ |x| safe_to_i(x) }
Can We Do Better? def safe_to_i(value) Integer(value) rescue nil end
['1','2','3','zero'].map{ |x| safe_to_i(x) } => [1, 2, 3, nil]
Can We Do Better? def safe_to_i(value) Integer(value) rescue nil end
['1','2','3','zero'].map{ |x| safe_to_i(x) } => [1, 2, 3, nil] ['1','2','3','zero'].map{ |x| safe_to_i(x) }.reduce(:+)
Can We Do Better? def safe_to_i(value) Integer(value) rescue nil end
['1','2','3','zero'].map{ |x| safe_to_i(x) } => [1, 2, 3, nil] ['1','2','3','zero'].map{ |x| safe_to_i(x) }.reduce(:+) TypeError: nil can't be coerced into Fixnum
Take Three
Take Three def safer_to_i(value) [Integer(value)] rescue [] end
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) }
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) } => [[1], [2], [3], []]
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten => [1, 2, 3]
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten => [1, 2, 3] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten.reduce(:+)
Take Three def safer_to_i(value) [Integer(value)] rescue [] end ['1','2','3','zero'].map{ |x|
safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten => [1, 2, 3] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.flatten.reduce(:+) => 6
But I Wanted To Fail!
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3'].map{ |x| safer_to_i(x) } => [[1], [2], [3]]
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3'].map{ |x| safer_to_i(x) } => [[1], [2], [3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3'].map{ |x| safer_to_i(x) } => [[1], [2], [3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence => [[1, 2, 3]]
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3','zero'].map{ |x| safer_to_i(x) } => [[1], [2], [3], []]
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3','zero'].map{ |x| safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence
But I Wanted To Fail! class Array def sequence self.reduce([[]]){
|a,b| a.flat_map{ |aa| b.map{ |bb| aa << bb }}} end end ['1','2','3','zero'].map{ |x| safer_to_i(x) } => [[1], [2], [3], []] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence => []
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]]
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) }
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) } => [6]
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) } => [6] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) } => [6] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence => []
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) } => [6] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence => [] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence .map{ |x| x.reduce(:+) }
But I Wanted To Fail! ['1','2','3'].map{ |x| safer_to_i(x) }.sequence =>
[[1, 2, 3]] ['1','2','3'].map{ |x| safer_to_i(x) }.sequence.map{ |x| x.reduce(:+) } => [6] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence => [] ['1','2','3','zero'].map{ |x| safer_to_i(x) }.sequence .map{ |x| x.reduce(:+) } => []
Where To Next?
Where To Next? def saferToInt(str: String): Option[Int] = try {
Some(str.toInt) } catch { case e: Exception => None } class ListOps[A](list: List[Option[A]]) { def sequence[A](a: List[Option[A]]): Option[List[A]] = a.foldRight[Option[List[A]]](Some(Nil))((a,b)=>a.flatMap(aa=>b.map(bb=>aa::bb))) def sequence: Option[List[A]] = sequence(list) } implicit def listToListOps[A](list: List[Option[A]]) = new ListOps(list)
Where To Next? List("1","2","3").map(saferToInt) res12: List[Option[Int]] = List(Some(1), Some(2), Some(3))
List("1","2","3").map(saferToInt).sequence res13: Option[List[Int]] = Some(List(1, 2, 3)) List("1","2","3").map(saferToInt).sequence.map(_.reduce(_+_)) res14: Option[Int] = Some(6)
Where To Next? List("1","2","3","zero").map(saferToInt) res16: List[Option[Int]] = List(Some(1), Some(2), Some(3),
None) List("1","2","3","zero").map(saferToInt).sequence res17: Option[List[Int]] = None List("1","2","3","zero").map(saferToInt).sequence.map(_.reduce(_+_)) res18: Option[Int] = None
Where To Next? This all works because List and Option
are Monads