Skip to content
This repository has been archived by the owner on Apr 18, 2022. It is now read-only.

[wip] Implement error handling using error-chain #332

Closed
wants to merge 2 commits into from

Conversation

derekdreery
Copy link
Contributor

This PR demonstrates the kind of way you would use error-chain to handle errors, and replaces all calls to expect/unwrap in the code and examples. Where I've created new error names to catch errors that were previously panicking, I'm not sure I've picked the right name, or that I'm capturing the right data, but at least this PR gives you a sense of how error handling could work.

It collects any errors in the parallel draw call into a vector.

The examples have been updated to use quick_main macro, which allows the "main" function to return a Result. If you run with RUST_BACKTRACE=1 cargo run ..., then whenever an error-chain error is created, a backtrace is attached, and reported if using quick_main.

@derekdreery
Copy link
Contributor Author

derekdreery commented Sep 4, 2017

I'm not sure of the impact on performance - you may want to silently ignore errors in production to run faster.

Also note that I haven't looked at amethyst itself yet - currently only the renderer builds.

@Rhuagh
Copy link
Member

Rhuagh commented Sep 4, 2017

Seems it's not working very well with ECS. Could you look into that?

@derekdreery
Copy link
Contributor Author

derekdreery commented Sep 4, 2017 via email

@Rhuagh
Copy link
Member

Rhuagh commented Sep 4, 2017

FWIW, I like it.

Copy link
Member

@Xaeroxe Xaeroxe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks quite informative! I like the approach. I can't merge this until at minimum CI passes, ideally I'd like this implemented for our other crates in this PR as well. Pinging @amethyst/engine-devs Is anyone opposed to this style of error management? Please leave a comment saying you're not if you are not so we don't just have total silence here.

@@ -1,5 +1,6 @@
//! Launches a new renderer window.

#[macro_use] extern crate error_chain;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Odd, I've been writing mine as

#[macro_use]
extern crate error_chain;

Is it documented anywhere what style these should be? I wasn't able to find documentation for this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I'm not requesting this be changed I just want to know if I've been doing mine wrong.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I typically have been doing it your way, but there are some merits to the one liner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm completely indifferent - I'll change to the amethyst standard :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you do cargo fmt?

Copy link
Member

@Aceeri Aceeri left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good stuff! Looks fine so far to me.

}

quick_main!(run);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future we should replace this with main again: rust-lang/rust#43301

error_chain! {
errors {
/// Failed to create a buffer.
BufferCreation(e: gfx::buffer::CreationError) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to docs here
when you wrap another error (not a chain) you put it into foreign_links block.
This will add From implementations automatically.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you will wrap this chain in main crate you need to add it in links block

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you use foreign_links, you gain ergonomics, but lose the ability to control the description (description is forwarded from contained error). I'll implement it using foreign_links, but want to note the trade-off.

@derekdreery
Copy link
Contributor Author

derekdreery commented Sep 5, 2017

Thanks for the replies, I'll implement this for all the crates

@derekdreery derekdreery changed the title Implement error handling using error-chain [wip] Implement error handling using error-chain Sep 5, 2017
@torkleyy torkleyy self-requested a review September 8, 2017 07:21
Copy link
Member

@torkleyy torkleyy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your work! Here are few things a noticed after reading over it.

@@ -37,6 +37,7 @@ rayon = "0.8"
serde = "1.0"
serde_derive = "1.0"
winit = "0.7"
error-chain = "0.10"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There already is 0.11 btw

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ty

@@ -1,5 +1,6 @@
//! Launches a new renderer window.

#[macro_use] extern crate error_chain;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you do cargo fmt?

}

quick_main!(run);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Examples should, if possible, avoid macros IMO.

Copy link
Contributor

@Emilgardis Emilgardis Sep 8, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

quick_main! could easily be replaced with how it is recommended to be done: link

fn main() {
    if let Err(ref e) = run() {
        use std::io::Write;
        let stderr = &mut ::std::io::stderr();
        let errmsg = "Error writing to stderr";

        writeln!(stderr, "error: {}", e).expect(errmsg);

        for e in e.iter().skip(1) {
            writeln!(stderr, "caused by: {}", e).expect(errmsg);
        }

        // The backtrace is not always generated. Try to run this example
        // with `RUST_BACKTRACE=1`.
        if let Some(backtrace) = e.backtrace() {
            writeln!(stderr, "backtrace: {:?}", backtrace).expect(errmsg);
        }

        ::std::process::exit(1);
    }
}

@torkleyy torkleyy added project: debugging type: improvement An improvement or change to an existing feature. labels Sep 8, 2017
use std::fmt::{Display, Formatter};
use std::fmt::Result as FmtResult;
use std::result::Result as StdResult;

use gfx;
use gfx_core;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not recommended error_chain usage. It is advised to use paths from root, i.e ::gfx_core::*

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, if it works I don't see any problems.

@@ -65,6 +65,11 @@
#![deny(missing_docs)]
#![doc(html_logo_url = "https://tinyurl.com/jtmm43a")]

// for error-chain
#![recursion_limit="4096"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have 4096 as the limit?
error_chain recommends 1024, and if I remember correctly, newer rust versions have this limit already set to 1024.

@derekdreery
Copy link
Contributor Author

derekdreery commented Sep 8, 2017 via email

@zakarumych
Copy link
Member

This feature becomes rather important as hierarchy of errors in amethyst grows.

@derekdreery
Copy link
Contributor Author

I'm currently trying to understand the asset loader, so I can do an error chain. I need to have a think, because at the moment errors are not concrete types.

@zakarumych
Copy link
Member

errors are not concrete types.

@derekdreery what do you mean?

@derekdreery
Copy link
Contributor Author

derekdreery commented Sep 20, 2017

An example of a generic error would be

#[derive(Clone, Debug)]
pub enum LoadError<A, F, S> {
    /// The conversion from data -> asset failed.
    AssetError(A),
    /// The conversion from bytes -> data failed.
    FormatError(F),
    /// The storage was unable to retrieve the requested data.
    StorageError(S),
}

I'm still exploring where these are specialised into concrete types. If that's done in user code, it may be necessary to use trait objects. Another option would be to remove the generics from these errors, and let the user put anything implementing Error into the chain. It might be easier if I ask some questions, maybe on gitter? I'll have to see if I have time to work on this today.

@zakarumych
Copy link
Member

@derekdreery LoadError is instantiated for Loader functions

@Xaeroxe
Copy link
Member

Xaeroxe commented Sep 28, 2017

Out of 12 files changed 10 now have conflicts. It'd probably be easier to rewrite this PR rather than try and re-merge it at this point. If you disagree with me @derekdreery I'll re-open this but for now I'm closing it.

For future PR authors: Large architecture overhauls that hit multiple function signatures and existing processes have to be completed quickly or they rapidly become changes to outdated code. This PR has been open for almost a month now.

@Xaeroxe Xaeroxe closed this Sep 28, 2017
@derekdreery
Copy link
Contributor Author

I agree.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
type: improvement An improvement or change to an existing feature.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants