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
Ben Darfler
May 06, 2015
Programming
160
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Error Handling Without Exceptions
A quick jaunt through functional error handling patterns using Ruby
Ben Darfler
May 06, 2015
More Decks by Ben Darfler
See All by Ben Darfler
Self-healing Software
bdarfler
0
160
Microservice Architectures
bdarfler
0
110
dotfiles
bdarfler
0
120
Remote Work
bdarfler
0
210
Low Latency Systems: How do they do it?
bdarfler
0
92
Scala
bdarfler
0
160
HTTP/2
bdarfler
0
160
Rails Asset Pipeline and You
bdarfler
0
100
How to Win at the Internet
bdarfler
1
57
Other Decks in Programming
See All in Programming
komatsuna「分散システムにおけるバグ分析手法」
komatsunaqa
0
250
人間の目はかわらない、だからJPEGは30年もつ
yuzneri
12
18k
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
490
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
180
「人を評価する AI」の設計と実装
ryoyanara
0
190
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.9k
プロポーザルを書いてもらう
pvcresin
0
310
Android CLI
fornewid
0
220
仕様駆動開発の消費期限
watany
20
8k
Google Apps Script で Ruby を動かす
kawahara
0
150
Cloudflare is Agents
chimame
0
160
Laravelで学ぶ Webアプリケーションチューニング入門/web_application_tuning_101
hanhan1978
4
1.7k
Featured
See All Featured
Claude Code のすすめ
schroneko
67
230k
Build your cross-platform service in a week with App Engine
jlugia
234
19k
Are puppies a ranking factor?
jonoalderson
1
3.8k
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
350
Typedesign – Prime Four
hannesfritz
42
3.1k
Prompt Engineering for Job Search
mfonobong
0
400
Kristin Tynski - Automating Marketing Tasks With AI
techseoconnect
PRO
0
440
Agile that works and the tools we love
rasmusluckow
331
22k
How STYLIGHT went responsive
nonsquared
100
6.2k
Between Models and Reality
mayunak
4
390
Winning Ecommerce Organic Search in an AI Era - #searchnstuff2025
aleyda
1
2.1k
Amusing Abliteration
ianozsvald
1
240
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