Why do crates overload the std::result::Result type? | tree_ds

So I was trying to use the tree_ds crate for a tree datastructure and found the crate is “overloading” the Result keyword to represent more of an Option, since the crate’s error types are private. The crate also expects you to use it via a pelude import, which is why I didn’t notice this at first.

use tree_ds::prelude::*;

...
//Result after prelude import
fn do_stuff() -> Result<T> {}
//How to get standard Result<T, E> back:
fn do_stuff() -> std::result::Result<T, E> {}

//Restricting the prelude import fixes this
use tree_ds::prelude{Node, Tree};

Restricting the prelude import fixes this, (not sure that is really workable in the long run, and sort of defeats the point of a prelude, doesn’t it?), but I am a bit curious why one would design an API this way, especially because the crate only really exposes the prelude to import?

Well it's pretty common to "overload"/define a type alias for core::result::Result when at least one of the types is fixed. For example, core::fmt::Result and std::io::Result are both type aliases for Result where the error type is core::fmt::Error and std::io::Error respectively. The reason for this is the same for most type aliases: to simplify the type.

The issue here is that tree_ds::prelude contains their defined Result alias. I think that is poor design seeing as the whole point of a "prelude" is the expectation that importing makes your life easier as a developer. If a "prelude" causes name collisions though, then this violates that goal. Of course one cannot avoid all collisions since one doesn't know what other crates and imports code will have; but almost all code relies on core which automatically imports core::result::Result, so having a Result in a prelude like this seems "wrong".

Personally, I don't define "prelude" mods in my own crates nor do I use "prelude" mods in other crates other than core/std (which are automatically imported). Here I'd rename the mod to something else; and if a developer ends up importing all items in it causing a collision, then that's on them.

4 Likes

Thank you. Yes, I was tripped up by this because the underlying error type is not public, which makes error handling a bit strange.

Yes, it definetly confused me until I figured out it was doing this. What makes it a bit stranger ist that the underlying error type is private (I am not sure that is intentional?), which makes interacting with it strange.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.