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
Failing in Rust
Search
Armin Ronacher
April 24, 2018
Programming
1k
5
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Failing in Rust
A quick talk at a meetup about using failure.
Armin Ronacher
April 24, 2018
More Decks by Armin Ronacher
See All by Armin Ronacher
Reflections on building cloud and local hybrid machine entities
mitsuhiko
1
200
Agentic Coding: The Future of Software Development with Agents
mitsuhiko
0
940
Do Dumb Things
mitsuhiko
0
1k
No Assumptions
mitsuhiko
0
450
The Complexity Genie
mitsuhiko
0
350
The Catch in Rye: Seeding Change and Lessons Learned
mitsuhiko
0
460
Runtime Objects in Rust
mitsuhiko
0
450
Rust at Sentry
mitsuhiko
0
620
Overcoming Variable Payloads to Optimize for Performance
mitsuhiko
0
320
Other Decks in Programming
See All in Programming
AI活用は、個人から組織へ|マルチプレイヤーエージェントハーネス「QM」の社内活用事例 / AI use is moving from individuals to orgs
rkaga
1
170
Starting & Sustaining Code-Based E2E Testing for Non-Coding QA Teams( #jasstniigata )
teyamagu
PRO
1
500
手動確認はもう限界 〜XCUITestでCustom URL Schemeの遷移を起動種別ごとに自動テストする〜 / Testing Custom URL Schemes with XCUITest
otouto
0
330
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
150
Jetpack Compose メカニズム
skydoves
0
470
The Good Stuff, Not the Slop: Engineering High-Quality Android Apps with Modern AI Tooling
danybony
1
260
TiDB Cloudのカスタムコントローラーによるオートスケール対応
takaidohigasi
0
130
Family mrubyの進捗
kishima
1
130
選挙速報を多くのユーザーへ 届ける Live Activities 設計
hamayokokuririn
0
160
標準パッケージに uuid が追加された 背景から見る Go らしい意思決定 / go_127_uuid_decision
convto
5
8.2k
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
180
モジュールの視点からSwiftを読み解く #iosdc
s_shimotori
0
190
Featured
See All Featured
A Guide to Academic Writing Using Generative AI - A Workshop
ks91
PRO
1
480
The World Runs on Bad Software
bkeepers
PRO
72
12k
Art, The Web, and Tiny UX
lynnandtonic
304
22k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
460
SEO for Brand Visibility & Recognition
aleyda
0
4.7k
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.6k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
16
2.2k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
31
10k
VelocityConf: Rendering Performance Case Studies
addyosmani
331
25k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
480
Sam Torres - BigQuery for SEOs
techseoconnect
PRO
0
550
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
?