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
150
0
Share
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
100
dotfiles
bdarfler
0
120
Remote Work
bdarfler
0
210
Low Latency Systems: How do they do it?
bdarfler
0
89
Scala
bdarfler
0
150
HTTP/2
bdarfler
0
150
Rails Asset Pipeline and You
bdarfler
0
94
How to Win at the Internet
bdarfler
1
52
Other Decks in Programming
See All in Programming
TSKaigi2026-静的解析への投資がAI時代のコード品質を支える ── カスタムESLintルールの設計と運用
hayatokudou
7
1.3k
Migrations : C'est une question d'hygiène !
vinceamstoutz
0
2.8k
自動レビューエンジンの実装と運用 ~レビューのない世界へ~
kurukuru1999
2
310
気づいたらRubyで100作品 ー クリエイティブコーディングが生活の一部になるまで / 100 Ruby Sketches Later: How Creative Coding Became Part of My Life
chobishiba
3
530
サーバーレスで作る、動画データ管理基盤
oyasumipants
0
340
TypeSpec で繋ぐ複数プロダクトの型安全
maroon8021
1
310
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
1
580
Old Dog, New Tricks: The Java 25 Reinvention - JNation
bazlur_rahman
0
140
IBM Bobを活用したレガシーアプリの最新化
oniak3ibm
PRO
0
120
[2026年度第1回ORセミナー] 計画最適化ベンチャーと競技プログラミング人材
terryu16
0
230
ビジネスモデルから紐解く、AI+型駆動開発
hirokiomote
2
5.1k
TSKaigi 2026 TypeScriptバックエンドのオブザーバビリティ戦略 — Datadog × NestJSの実践
taiseiyamamotoan
1
210
Featured
See All Featured
Exploring the Power of Turbo Streams & Action Cable | RailsConf2023
kevinliebholz
37
6.5k
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
720
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
55k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
380
Game over? The fight for quality and originality in the time of robots
wayneb77
1
180
Ruling the World: When Life Gets Gamed
codingconduct
0
240
Everyday Curiosity
cassininazir
0
220
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Exploring the relationship between traditional SERPs and Gen AI search
raygrieselhuber
PRO
2
4k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
350
Building an army of robots
kneath
306
46k
How To Speak Unicorn (iThemes Webinar)
marktimemedia
1
470
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