Skip to content

Relationship between Diagnostic and StdError #164

@TheNeikos

Description

@TheNeikos

I would like to understand where miette currently tries to position itself in the 'Rust error story'. To do this, I'm opening this issue to see what I might have missed and/or not understood correctly.


Miette exposes a Diagnostic trait that extends on top of the Error trait with additional information so as to report better looking and more informative errors.

To do so, it currently imposes the following relationship Diagnostic: StdError (StdError is a supertrait of Diagnostic). This means that any Diagnostic is also an StdError.
StdError has multiple advantages that speak for it:

  • It requires a 'Display' implementation, forcing developers to give a textual representation of the error that is fit for 'end-user consumption'.
  • It has a .source/cause method that gives access to the error that 'cause'd it

Diagnostic builds on top of this with the ability to specify spans with labels, severity, etc... .
This gives it several nice things that seperate it from StdError:

  • Users can be more precisely informed with visual language on where errors occured
  • Colors (through severity) give them a color indicator on how 'bad' or useful the information is
  • Through the .source method of StdError on can get access to the underlying errors and print those too, potentially going as far as to the root error that caused it.

This means that for a given Diagnostic and finally Report one can have the following relationship:


             ┌────────┐
     ┌───────┤ Report ├────┐
     │       └────────┘    │
     │                     │
     │                     │
┌────▼─────┐          ┌────▼─────┐
│Diagnostic│          │Diagnostic│
└────┬─────┘          └─────┬────┘
     │                      │
     │                      │
     │                      │
 ┌───▼────┐            ┌────▼───┐
 │StdError│            │StdError│
 └────────┘            └────┬───┘
                            │
                            │
                            │
                       ┌────▼───┐
                       │StdError│
                       └────────┘

Important to note is that while the Top-level Diagnostic/Report has multiple 'Diagnostics' below it, they are currently only 'related'. (For example multiple logically distinct errors in a configuration file).

It is also not possible to 'chain' Diagnostics, as there is no .source equivalent for Diagnostic. This means that either a single diagnostic is created at the root (potentially wrapping a StdError) and then transported all the way to the base or that extra information is added later on. (Through for example the with_source_code transforms). An error, once made into a Diagnostic cannot be re-integrated into the chain of errors except as a logically distinct 'related' issue.


To me, this disconnect feels weird (and is mostly due to Rust constraints from its current state). I was expecting that I could effectively represent a 'tree' of Diagnostics with the following relationship:

                         ┌────────┐
                 ┌───────┤ Report ├────┐
                 │       └────────┘    │
                 │                     │
                 │                     │
            ┌────▼─────┐          ┌────▼─────┐
            │Diagnostic│          │Diagnostic├────────┐
            └────┬─────┘          └────┬─────┘        │
                 │                     │              │
                 │                     │              │
                 │                     │              │
┌────────┐  ┌────▼─────┐          ┌────▼─────┐   ┌────▼─────┐   ┌────────┐
│StdError├──►Diagnostic│          │Diagnostic│   │Diagnostic◄───┤StdError│
└────────┘  └──────────┘          └────┬─────┘   └──────────┘   └────────┘
                                       │
                                       │
                                       │
                                  ┌────▼─────┐
                                  │Diagnostic│
                                  └──────────┘

Where any StdError could be converted to a Diagnostic to be used as part of the tree of errors an application may expose but that Diagnostic does not require the supertrait Error anymore.

This brings its own problems with it though, as now libraries that expose a Diagnostic has no direct compatibility to std::error::Error.

From what I understand, this is currently heavily geared towards maximum compatibility with the StdError ecosystem but at the same time Report does not implement StdError anyway.

This leaves me wondering, why does Diagnostic require Error as a supertrait? If one wants to keep compatibility with StdError then one can just implement it (with thiserror or manually). If Diagnostic simply has a Display bound, then they are even compatible together (since thiserror implements Display for you too).


NB: English is not my first language, and I hope I didn't miss my tone here: I am trying to understand how Miette came to be and where it would like to be in the future?


This is maybe related to #139?
I am using StdError to disambiguate on "Error"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions