2

Suppose I want to write a doc comment such as this:

//! This type can be used to write a function such as:
//! ```
//! fn example() -> MyType { ... }
//! ```
//! Then the function can be used as:
//! ```
//! example()
//! ```

Currently the doc test of the second snippet does not compile because the example function from the first snippet is not in scope.

However, in my concrete example the first snippet is quite long, so it's tedious to copy/paste the first snippet into the second to make the latter compile.

Is there a way to import things defined in a snippet into scope in another snippet?

1 Answer 1

5

Technically, yes. It is a very bad idea, though.

The reason this is not a built-in feature is because two separate doc-tests may both define example(). Because doc-tests are not named, it would not be possible to disambiguate which example() you want the second doc-test to use. If your example worked, adding a third, seemingly unrelated doc-test that also defines an example() would cause this to fail.

Prior to Rust 2024, every doc-test was compiled into a separate crate, making what you want to happen completely impossible. However, in Rust 2024, Rust "attempts" to combine doc-tests into a single crate.

This blog post explains how doc-tests are compiled together: they are placed in separate, private mods, to prevent the naming conflicts described above. However, because they are in the same crate, you can technically still access them using #[unsafe(no_mangle)] and extern blocks. I can't reiterate enough just how much of a bad idea actually doing this is - as stated in no_mangles documentation, it is undefined behavior if "unmangled [symbols] collide with another symbol with the same name (or with a well-known symbol)". On top of that, it is certainly not guaranteed that doc-tests that are currently compiled in the same crate will continue to do so in future versions of Rust - the edition guide only lists "examples" where functions may be placed in separate crates, presumably meaning that adding situations where tests are compiled in separate crates is not considered a breaking change.

With those caveats out of the way, and mostly as a thought experiment, the following works on my machine:

//! ```rust
//! # use playground::MyType;
//! # #[unsafe(no_mangle)]
//! fn example() -> MyType { /* long implementation */ }
//! ```
//! Then the function can be used as:
//! ```rust
//! # unsafe extern "Rust" { pub safe fn example(); }
//! example();
//! ```

Again, a very bad idea. If you want the recommended solution to your particular problem, you have three choices here - either just add a dummy implementation of example to the second doc-test, use the ignore doc-test attribute, or combine the doc-tests into one.

Dummy implementation: (the reason why example is called in the first one is to actually test the long implementation.)

//! ```rust
//! # use my_crate::MyType;
//! fn example() -> MyType { /* long implementation */ }
//! # example();
//! ```
//! Then the function can be used as:
//! ```rust
//! # use my_crate::MyType;
//! # fn example() -> MyType { /* dummy implementation */ }
//! example();
//! ```

ignore:

//! ```rust
//! # use my_crate::MyType;
//! fn example() -> MyType { /* long implementation */ }
//! # example();
//! ```
//! Then the function can be used as:
//! ```rust,ignore
//! example();
//! ```

Single doc test:

//! ```rust
//! # use my_crate::MyType;
//! fn example() -> MyType { /* long implementation */ }
//! 
//! // Now the function can be invoked like this:
//! example();
//! ```

The first and second ones will look like this:

fn example() -> MyType { /* long implementation */ }

Then the function can be used as:

example();

And the third like this:

fn example() -> MyType { /* long implementation */ }
 
// Now the function can be invoked like this:
example();
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! I understand your remarks about naming issue, although maybe if the compiled combined snippets from the same doc comment code, naming issues would be less relevant?
They would be exactly as relevant, the problem isn't within the same doc comment or related doc comments. The problem is with different, completely unrelated doc comments.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.