Skip to content
This repository has been archived by the owner on Sep 12, 2024. It is now read-only.

Should recovering the type_name of a dyn Error be supported? #52

Open
thomcc opened this issue May 2, 2022 · 2 comments
Open

Should recovering the type_name of a dyn Error be supported? #52

thomcc opened this issue May 2, 2022 · 2 comments

Comments

@thomcc
Copy link
Member

thomcc commented May 2, 2022

It would be nice (IMO) if there were a way to recover the type name (as produced by core::any::type_name1) of a dyn Error. I've wanted this several times, as in many cases, it can be useful as a summary of what went wrong at a fairly high level, and without any details (since the details are available through other means, such as the Debug/Display implementations).

(A concrete use case I've recently hit involves serializing Error instances for remote reporting, where the type name could be useful for broad categorization. That said, for my case it is not a problem to capture this information when the error is generated, before its type is erased. So... I don't know how compelling this example is)

On the other hand, perhaps this isn't worth having. In principal, enough information to figure out what type the error initially had should probably be present in the Debug output. And it may be too similar to Error::description(), which we deprecated -- presumably (I don't actually know the reason) for being inflexible and redundant, which are arguably flaws this would have as well. Also, the fact that I was able to capture this prior to type erasure without much pain indicates that perhaps this would be true for most other situations where it's needed.

If we do want it, I think it would be straightforward to implement -- I'm imagining that this would just be a type_name(&self) -> &'static str on the error trait, and would have an implementation similar to that of Error::type_id. I think it would have the same non-guarantees that core::any::type_name has for consistency, accuracy, etc. (Also, while I don't see a reason to allow users to override it, I don't really see a reason to forbid it either -- It's not like anybody can trust it being accurate or consistent, after all). That said, I don't feel very strongly about these implementation details -- you certainly could design it other ways (including repurposing Error::description(), although this would certainly not be my suggestion).

(P.S. Sorry if this has been discussed, I didn't see it)

Footnotes

  1. Note that while core::any::type_name_of_val exists and seems like it would support trait objects, it doesn't (at least, not really -- it essentially just reports dyn std::error::Error). I believe this is intentional, and that it probably will due to the nontrivial binary size cost this would incur, even for code that doesn't use it.

    This is discussed in the type_name_of_val tracking issue, and despite my desire to have type names work for Error instances, I don't think I would be in favor of it work on all trait objects; due to said cost.

    That said, for errors it makes sense to me, for the reason mentioned above (it can be a useful high-level summary of what went wrong).

@yaahc
Copy link
Member

yaahc commented May 2, 2022

On the other hand, perhaps this isn't worth having. In principal, enough information to figure out what type the error initially had should probably be present in the Debug output. And it may be too similar to Error::description(), which we deprecated -- presumably (I don't actually know the reason) for being inflexible and redundant, which are arguably flaws this would have as well. Also, the fact that I was able to capture this prior to type erasure without much pain indicates that perhaps this would be true for most other situations where it's needed.

My understanding is that description was deprecated because it's signature was to just return a &str, so it didn't allow for runtime context to be included without preformatting the string and holding the backing storage for the str in the error itself. If I could go back and change everything I think I'd make it so that description was fn description(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result and have Display be a blanket impl for all error types that does the common case of printing the error and it's sources on a single line, and possibly use the alt flag to print errors on multiple lines.

(P.S. Sorry if this has been discussed, I didn't see it)

This hasn't been discussed before that I can recall, so you're good.

Is it currently possible to do this for a &dyn Any? I made a basic attempt but was only able to get dyn Any as the type_name. https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=3d52f1d764039ed4f50089af1f6d5f09

In my mind, the only reason Error has any of this type erasure machinery is because it isn't possible to have compound vtables like dyn Error + Any. I would like to preserve that equivalence as much as possible, so I wouldn't be in favor of adding this to dyn Error unless similar functionality was adopted for dyn Any.

@thomcc
Copy link
Member Author

thomcc commented May 3, 2022

Is it currently possible to do this for a &dyn Any? I made a basic attempt but was only able to get dyn Any as the type_name.

No. I suspect supporting this for dyn Any would have a much larger cost in terms of code size than only doing it for error, although it would still be less than supporting it for all trait objects, so perhaps the cost would be low enough not to matter.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants