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
Failing in Rust
Search
Armin Ronacher
April 24, 2018
Programming
5
1k
Failing in Rust
A quick talk at a meetup about using failure.
Armin Ronacher
April 24, 2018
Tweet
Share
More Decks by Armin Ronacher
See All by Armin Ronacher
Agentic Coding: The Future of Software Development with Agents
mitsuhiko
0
550
Do Dumb Things
mitsuhiko
0
870
No Assumptions
mitsuhiko
0
340
The Complexity Genie
mitsuhiko
0
290
The Catch in Rye: Seeding Change and Lessons Learned
mitsuhiko
0
400
Runtime Objects in Rust
mitsuhiko
0
380
Rust at Sentry
mitsuhiko
0
550
Overcoming Variable Payloads to Optimize for Performance
mitsuhiko
0
270
Rust API Design Learnings
mitsuhiko
0
630
Other Decks in Programming
See All in Programming
AI Schema Enrichment for your Oracle AI Database
thatjeffsmith
0
350
24時間止められないシステムを守る-医療ITにおけるランサムウェア対策の実際
koukimiura
1
160
余白を設計しフロントエンド開発を 加速させる
tsukuha
7
2.1k
Event Storming
hschwentner
3
1.3k
個人開発は儲からない - それでも開発開始1ヶ月で300万円売り上げた方法
taishiyade
0
110
要求定義・仕様記述・設計・検証の手引き - 理論から学ぶ明確で統一された成果物定義
orgachem
PRO
1
310
今から始めるClaude Code超入門
448jp
8
9.3k
AI時代の認知負荷との向き合い方
optfit
0
180
360° Signals in Angular: Signal Forms with SignalStore & Resources @ngLondon 01/2026
manfredsteyer
PRO
0
170
AIによる高速開発をどう制御するか? ガードレール設置で開発速度と品質を両立させたチームの事例
tonkotsuboy_com
7
2.5k
Rubyと楽しいをつくる / Creating joy with Ruby
chobishiba
0
160
JPUG勉強会 OSSデータベースの内部構造を理解しよう
oga5
1
180
Featured
See All Featured
Bootstrapping a Software Product
garrettdimon
PRO
307
120k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.3k
30 Presentation Tips
portentint
PRO
1
230
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
47
8k
The untapped power of vector embeddings
frankvandijk
1
1.6k
My Coaching Mixtape
mlcsv
0
55
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
450
16th Malabo Montpellier Forum Presentation
akademiya2063
PRO
0
54
Impact Scores and Hybrid Strategies: The future of link building
tamaranovitovic
0
210
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.1k
Agile that works and the tools we love
rasmusluckow
331
21k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Transcript
Failing in Rust Armin @mitsuhiko Ronacher
None
800°C 36° 2' 0.4662" N 118° 15' 38.7792" W 795°C
789°C 797°C 793°C 805°C 782°C we show you your crashes
— Robert F. Kennedy “Only those who dare to fail
greatly can ever achieve greatly.”
Why do we care?
Errors are Important • Errors are part of your API
• Exceptions let you forget about this easily • A lot more relevant when you can catch them and there are multiple versions of libraries involved
ways to fail greatly
Mechanisms •Result<T, E> •Option<T> •panic!
Result Propagation vs Panic • Results/Options are for handling •
panics are for recovering at best
Examples of Panics • out of bound access • runtime
Examples of Option • safe signalling absence of data •
"the one obvious error"
— Douglas Adams
But when you do •panic!("…"); •unreachable!();
let's talk results
But if you don't panic … how do you result?
fn square_a_number() -> Result<f32, E> { let num = get_a_random_float()?;
Ok(num * num) }
let val = expr?;
let val = match Try::into_result(expr) { Ok(v) => v, Err(e)
=> return Try::from_error(From::from(e)); };
error propagation can be hooked!
The Err in Result can be anything :-/
So let's use some traits for Err
pub trait Error: Debug + Display { fn description(&self) ->
&str; fn cause(&self) -> Option<&Error>; }
impl Error + 'static { pub fn downcast_ref<T>(&self) -> Option<&T>
where T: Error + 'static; }
— Charles Darwin “To kill std::error is as good a
service as, and sometimes even better than, the establishing of a new trait”
Problems • Generic errors give no guarantees • no Send
/ Sync / Debug • causes() returns non static errors • description() is useless • no backtraces
Enter Failure
— Winston Churchill “Success consists of going from std::error to
failure without loss of enthusiasm”
some std errors are fails nice! impl<E> Fail for E
where E: StdError + Send + Sync + 'static
failure 0.1 ➠ failure 1.0
pub trait Fail: Display + Debug + Send + Sync
+ 'static { fn cause(&self) -> Option<&Fail>; fn backtrace(&self) -> Option<&Backtrace>; fn context<D>(self, context: D) -> Context<D> where D: Display + Send + Sync + 'static, Self: Sized; }
Fail can be derived
#[derive(Fail, Debug)] #[fail(display = "my failure happened")] pub struct MyFailure;
#[derive(Fail, Debug)] #[fail(display = "my failure happened")] pub struct MyFailure
{ backtrace: failure::Backtrace, }
#[derive(Fail, Debug)] #[fail(display = "my failure happened")] pub struct MyFailure
{ backtrace: failure::Backtrace, #[fail(cause)] io_cause: ::std::io::Error, }
Fail & Error
Fail ⟷ Error
Fail for libraries Error for applications
What's in the Package
Main Functionality • Fail trait • Error type • Context
Bonus Points • Fail works with no_std • Fail works
with many std::errors • error-chain is deprecating itself for failure • actix and others are already using it!
— rustc an Error is not a Fail
failure 0.1: error.cause() failure 1.0: error.as_fail() Error to &Fail
Examples
#[derive(Debug, Fail, PartialEq, Eq, PartialOrd, Ord)] #[fail(display = "invalid value
for project id")] pub struct ProjectIdParseError; Parse Errors
#[derive(Debug, Fail)] pub enum DsnParseError { #[fail(display = "no valid
url provided")] InvalidUrl, #[fail(display = "no valid scheme")] InvalidScheme, #[fail(display = "username is empty")] NoUsername, #[fail(display = "no project id")] NoProjectId, #[fail(display = "invalid project id")] InvalidProjectId(#[fail(cause)] ProjectIdParseError), } Complex Parse Errors
fn parse(url: Url) -> Result<Dsn, DsnParseError> { let project_id: i64
= url.path() .trim_matches('/') .parse() .map_err(DsnParseError::InvalidProjectId)?; Ok(Dsn { project_id }) } Mapping Errors
#[derive(Debug, Fail, Copy, Clone, PartialEq, Eq, Hash)] pub enum ErrorKind
{ #[fail(display = "governor spawn failed")] TroveGovernSpawnFailed, #[fail(display = "governor shutdown failed")] TroveGovernShutdownFailed, } Error Kinds
#[derive(Debug)] pub struct Error { inner: Context<ErrorKind>, } Custom Errors
impl Fail for Error { fn cause(&self) -> Option<&Fail> {
self.inner.cause() } fn backtrace(&self) -> Option<&Backtrace> { self.inner.backtrace() } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.inner, f) } } Error Pass Through
pub fn run(config: Config) -> Result<(), Error> { let trove
= Arc::new(Trove::new(config)); trove.govern().context(ErrorKind::TroveGovernSpawnFailed)?; // … } Example Usage
use failure::{Error, ResultExt}; pub fn attach_logfile(&mut self, logfile: &str) ->
Result<(), Error> { let f = fs::File::open(logfile) .context("Could not open logfile")?; let reader = BufReader::new(f); for line in reader.lines() { let line = line?; User Facing with Error
A person who never made a mistake never had to
write an error API
?