- Feature Name:
public_private_dependencies
- Start Date: 2017-04-03
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Introduce a public/private distinction to crate dependencies.
The crates ecosystem has greatly expanded since Rust 1.0 and with that a few patterns for
dependencies have evolved that challenge the currently existing dependency declaration
system in cargo and rust. The most common problem is that a crate A
depends on
another crate B
but some of the types from crate B
are exposed through the API in
crate A
. This causes problems in practice if that dependency B
is also used by the
user's code itself which often leaves users in less than ideal situations where either
their code refuses to compile because different versions of those libraries are requested
or where compiler messages are less than clear.
The introduction of an explicit distinction between public and private dependencies can solve some of these issues and also let us lift some restrictions that should make some code compile that previously was prevented from compiling by restrictions in cargo.
Q: What is a public dependency?
A: a dependency is public if some of the types or trait of that dependency is itself
exported through the main crate. The most common places where this happens is obviously
return values and function parameter but obviously the same applies to trait implementations
and many other things. Because public can be tricky to determine for a user this RFC
proposes to extend the compiler infrastructure to detect the concept of "public dependency".
This will help the user understanding this concept and avoid making mistakes in
the Cargo.toml
Effectively the idea is that if your own library bumps a public dependency it means that it's a breaking change of your own crate.
Q: What is a private dependency?
A: On the other hand a private dependency is contained within your crate and effectively
invisible for users of your crate. As a result private dependencies can be freely
duplicated. This distinction will also make it possible to relax some restrictions that
currently exist in Cargo which sometimes prevent crates from compiling.
Q: Can public become private later?
A: Public dependencies are public within a reachable subgraph but can become private if a
crate stops exposing a public dependency. For instance it is very possible to have a
family of crates that all depend on a utility crate that provides common types which is
a public dependency for all of them. However your own crate only becomes a user of this
utility crate through another dependency that itself does not expose any of the types
from that utility crate and as such the dependency is marked private.
Q: Where is public / private defined?
Dependencies are private by default and are made public through a public
flag in the
dependency in the Cargo.toml
file. This also means that crates created before the
implementation of this RFC will have all their dependencies private.
Q: How is backwards compatibility handled?
A: It will continue to be permissible to "leak" dependencies and there are even some
use cases of this, however the compiler or cargo will emit warnings if private
dependencies become part of the public API. Later it might even become invalid to
publish new crates without explicitly silencing these warnings or marking the
dependencies as public.
Q: Can I export a type from a private dependency as my own?
For now it will not be strictly permissible to privately depend on a crate and export
a type from their as your own. The reason for this is that at the moment it is not
possible to force this type to be distinct. This means that users of the crate might
accidentally start depending on that type to be compatible if the user starts to depend
on the crate that actually implements that type.
There are a few areas that require to be changed for this RFC:
- The compiler needs to be extended to understand when crate dependencies are considered a public dependency
- The
Cargo.toml
manifest needs to be extended to support declaring public dependencies - The cargo publish process needs to be changed to warn (or prevent) the publishing of crates that have undeclared public dependencies
- crates.io should show public dependencies more prominently than private ones.
XXX: add me
In some situations it can be necessary to allow private dependencies to become
part of the public API. In that case one can permit this with
#[allow(external_private_dependency)]
. This is particularly useful when
paired with #[doc(hidden)]
and other already existing hacks.
The Cargo.toml
file will be amended to support the new public
parameter on
dependencies. Old cargo versions will emit a warning when this key is encountered
but otherwise continue. Since the default for a dependency to be private only
public ones will need to be tagged which should be the minority.
Example dependency:
[dependencies]
url = { version = "1.4.0", public = true }
When a new crate version is published Cargo will warn about types and traits that
the compiler determined to be public but did not come from a public dependency. For
now it should be possible to publish anyways but in some period in the future it will
be necessary to explicitly mark all public dependencies as such or explicitly
mark them with #[allow(external_private_dependency)]
.
What names and terminology work best for these concepts and why? How is this idea best presented—as a continuation of existing Rust patterns, or as a wholly new one?
Would the acceptance of this proposal change how Rust is taught to new users at any level? How should this feature be introduced and taught to existing Rust users?
What additions or changes to the Rust Reference, The Rust Programming Language, and/or Rust by Example does it entail?
Why should we not do this?
What other designs have been considered? What is the impact of not doing this?
What parts of the design are still TBD?