How does Rust control scope and privacy? Does it automatically infer? - rust

I have code like this:
mod _mod1 {
struct _A {}
pub(in crate::_mod1) mod _mod2 {
use super::_A;
pub struct _B {}
impl _B {
pub fn _test(_a: _A) {}
}
}
}
And then I run cargo check, it tells me that "private type _A in public interface".
error[E0446]: private type `_A` in public interface
--> src/main.rs:9:13
|
2 | struct _A {}
| --------- `_A` declared as private
...
9 | pub fn _test(_a: _A) {}
| ^^^^^^^^^^^^^^^^^^^^ can't leak private type
For more information about this error, try `rustc --explain E0446`.
error: could not compile `mytest` due to previous error
In my opinion, in this code, although _test method is pub, mod _mod2 is pub(in crate::_mod1). struct _B and _test method can only be accessed in mod _mod1, which meets A's access requirements. Does Rust infer control scope and privacy?

Rust does not considers the privacy of the module when calculating this error, and for a good reason.
You could have reexported _B publicly in _mod1:
mod _mod1 {
struct _A {}
pub(in crate::_mod1) mod _mod2 {
use super::_A;
pub struct _B {}
impl _B {
pub fn _test(_a: _A) {}
}
}
pub use _mod2::B;
}
Now the code that has access to _mod1 has access to _B::_test(), too, and thus has access to _mod1::_A although it shouldn't as it is private.
In theory, maybe Rust could mitigate this risk by analyzing the whole module and detecting if the item is reexported, but in practice, this is both too expensive and unintuitive, and can cause unexpected failures when unrelated code changes (imagine a glob import that doesn't even mention the type).
So Rust only checks the privacy of the item itself.

Related

Why can you return a private struct from a closure

Rust normally has strict privacy laws, you can't return a private type from a public function.
However, it seems like you are able to return a type created in a closure from that closure. But why? Why are you allowed to return a private struct from a closure?
fn main () {
let closure = || {
struct Sample;
Sample
};
}
Because you can still do things with it. The structure isn't sealed inside the closure, it just so happens that we can't use the name Sample directly outside of the closure. But we can still access its methods. Consider
fn main () {
let closure = || {
struct Sample;
impl Sample {
fn say_hello(&self) {
println!("Hello, world! :)");
}
}
Sample
};
let s = closure();
s.say_hello();
}
The main function still knows that s has type Sample, and we can still call inherent methods like say_hello on it. The fact that you, as the programmer, can't say the name of the structure, is irrelevant.
Just to make it perfectly clear, based on feedback in the comments. Local structures and fn functions in Rust (i.e. structures and functions written inside other functions) are not actually local. They're internally hoisted to the enclosing module from a visibility standpoint. A function can't own a structure, only a module can. You can't reference the name Sample in the module scope, but that's where it's being hoisted to internally. If it helps, you can think of it as though Sample is being lifted to a top-level struct __mangledname_internal_Sample at the top of your file. It's still there, just not with a name that you can access.
Here's what's roughly being generated per your rust code:
struct Closure {
s : Sample
}
impl FnOnce<()> for Closure {
type Output = Sample;
fn call_once(self) -> Self::Output {
self.s
}
}
The information regarding defining the struct and the impl blocks are hoisted to the module level when inside of a closure. So this block below will be accessible at the module level:
struct Sample;
impl Sample {
fn say_hello(&self) {
println!("Hello, world! :)");
}
}
Therefore, nothing actually breaks the privacy rules as the Closure struct simply uses the Sample type defined at the module level
In your current code, you haven't yet actually done anything with the closure. Try this one:
fn main () {
let closure = some_stuff::public_function();
}
mod some_stuff {
pub fn public_function () -> impl FnOnce() -> PrivateStruct {
let closure = || {
struct PrivateStruct;
PrivateStruct
};
return closure
}
}
And you'll get
Compiling playground v0.0.1 (/playground)
error[E0412]: cannot find type `PrivateStruct` in this scope
--> src/lib.rs:6:51
|
6 | pub fn public_function () -> impl FnOnce() -> PrivateStruct {
| ^^^^^^^^^^^^^ not found in this scope
For more information about this error, try `rustc --explain E0412`.
error: could not compile `playground` due to previous error

resolving cyclic dependency between traits that need references to each other in rust

I have two structs that need references to each other. Due to other reasons these structs need to bypass borrow checker at the same time. So I have a wrapper around *mut T to bypass the checker. Now I am trying to have each struct have a generic type of the second struct.
This is a toy example:
use d2simrs::util::internalref::InternalRef;
pub trait Layer3Trait {
fn foo() {
println!("TraitA::foo()");
}
}
pub trait Layer2Trait {
fn bar() {
println!("TraitB::foo()");
}
}
pub struct SimpleLayer2<Layer3T>
where Layer3T: Layer3Trait
{
pub layer3: InternalRef<Layer3T>,
}
pub struct SimpleLayer3<Layer2T>
where Layer2T: Layer2Trait
{
pub layer2: InternalRef<Layer2T>,
}
pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer2Ref = InternalRef<Layer2>;
pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
pub type Layer3Ref = InternalRef<Layer3>;
Code for InternalRef is here
For which I get
|
30 | pub type Layer3 = SimpleLayer3<SimpleLayer2<Layer3>>;
| ^^^^^^
|
= note: ...which again requires computing type of `example2::Layer3`, completing the cycle
note: cycle used when computing type of `example2::Layer2`
--> examples/network/bypass_borrow/example2.rs:27:32
|
27 | pub type Layer2 = SimpleLayer2<Layer3>;
| ^^^^^^
Can I somehow re-define something, so that SimpleLayer2 and SimpleLayer3 can have references to one another.
Rust does not support cyclic generic types. If you have:
pub type Layer2 = SimpleLayer2<Layer3>;
pub type Layer3 = SimpleLayer3<Layer2>;
Then the concrete type of Layer3 would be:
SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<SimpleLayer2<SimpleLayer3<...>>>>>>>
Which is not allowed.
As nudged at in the comments, it would ideal if your design were heirachial with no cyclic dependencies since it would obviously avoid such problems. But if that is not appropriate, the standard way to solve this would be with Rc/Arcs and trait objects, which would also avoid your internal *mut T wrapper (with RefCell/RwLock if you need mutability):
use std::rc::{Rc, Weak};
pub struct SimpleLayer2 {
pub layer3: Weak<RefCell<dyn Layer3>>,
}
pub struct SimpleLayer3 {
pub layer2: Rc<RefCell<dyn Layer2>>,
}
See these other questions for other potential ideas:
Is there a way to build a structure with cyclic links without runtime overhead?
How do I express mutually recursive data structures in safe Rust?
Implement graph-like data structure in Rust

Can I use a trait with default implementations for all functions directly without a concrete implementation? [duplicate]

When calling a default implementation on a trait which does not take self, why does it neeed an implementing type to be annotated?
A minimal, reproducible example is below (playground):
mod builder {
pub trait Builder: Sized {
fn new() -> Simple {
Simple
}
}
pub struct Simple;
impl Builder for Simple {}
}
pub fn main() {
let _ = builder::Builder::new();
/* Working version */
// use builder::Builder;
// let _ = builder::Simple::new();
}
Which gives:
error[E0283]: type annotations needed
--> src/main.rs:14:13
|
3 | fn new() -> Simple {
| ------------------ required by `builder::Builder::new`
...
14 | let _ = builder::Builder::new();
| ^^^^^^^^^^^^^^^^^^^^^ cannot infer type
|
= note: cannot satisfy `_: builder::Builder`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0283`.
error: could not compile `playground`.
To learn more, run the command again with --verbose.
The compiler explanation for E0283 does not mention a default implementation, which I agree it makes sense. But for default implementations, why is a type required?
This is not only a default implementation but the very specific case in which this default implementation does not even mention Self/self in its parameters, result and body.
I find much more easy to understand a rule saying that a type is required every time we use a trait, in any case, rather that « except if the default implementation does not even mention Self/self in its parameters, result and body ».
For this very specific use case, where you do not want to explicitly name a type when calling the function you need, I suggest using a free function.
mod builder {
// ...
pub fn make_default() -> Simple {
Simple
}
// ...
}
pub fn main() {
let _ = builder::make_default();
}
Provided methods in Rust are not like static methods in Java. Even a function with no arguments and a default implementation can be overridden by implementors. Consider adding another type that implements Builder but overrides the new function:
struct Noisy {}
impl builder::Builder for Noisy {
fn new() -> builder::Simple {
println!("Ahahahah I'm creating a Simple!!!11!");
builder::Simple
}
}
fn main() {
// wait, should this call builder::Simple::new() or Noisy::new()?
let _ = builder::Builder::new();
}
If you want the effect of a Java static function that always has the same behavior, you should use a free function, as prog-fh's answer also suggests.

How can I make a struct non-public and not move it from lib.rs?

Consider this simple crate:
src/lib.rs
mod internal;
use internal::f;
pub(crate) struct Foo {}
pub fn g() {
f();
}
src/internal.rs
use Foo;
pub fn f() -> Foo {
unimplemented!();
}
I want to export only the g function from the crate. I also want to define Foo in lib.rs to simplify reading of my source code. This is an important struct for the crate, so I want to move it to the first
file that any potential reader would open.
The compiler reports:
error[E0446]: private type `Foo` in public interface
--> src/internal.rs:3:1
|
3 | / pub fn f() -> Foo {
4 | | unimplemented!();
5 | | }
| |_^ can't leak private type
How can I fix this issue? Why it is private, while it public for crate?
While it's not hard to catch this case, it would actually be inconsistent for pub to allow private types. pub means that the item may be usable outside the crate. It doesn't matter that you aren't reexporting it, it could be that you reexport it.
The decision is local to the item declaration in order to make it easy to see whether some item could be exposed. If you are in a random file in your project, you can see whether an item is definitely not exposed by either a missing pub specifier or by a constraint on pub. This significantly increases code readability.
For more detailed information, read the relevant RFC or in the tracking issue for the private_in_public lint

traits and associated-types

I'm trying to implement something on Rust with traits and associated types. I'm not sure how to form my question with words, so I'll add a code snippet which will hopefully illustrate what I'm trying to do.
pub trait Person {}
pub trait Directory<P: Person> {
type Per = P;
fn get_person(&self) -> Self::Per;
}
pub trait Catalog {
type Per : Person;
type Dir : Directory<Self::Per>;
fn get_directory(&self) -> Self::Dir;
}
fn do_something<C>(catalog: C) where C: Catalog {
let directory : C::Dir = catalog.get_directory();
// let person : C::Per = directory.get_person();
// The code above fails with:
// error: mismatched types:
// expected `<C as Catalog>::Per`,
// found `<<C as Catalog>::Dir as Directory<<C as Catalog>::Per>>::Per`
// (expected trait `Catalog`,
// found trait `Directory`) [E0308]
let person = directory.get_person();
do_something_with_person(person);
}
fn do_something_with_person<P: Person>(p: P) {}
I would expect that the above code would compile, but it does not.
Instead, I get:
error: the trait `Person` is not implemented for the type `<<C as Catalog>::Dir as Directory<<C as Catalog>::Per>>::Per` [E0277]
Which, AFAICT, means that the compiler cannot determine that the person variable has the Person trait.
I'm using the following rustc version:
rustc 1.2.0-dev (a19ed8ad1 2015-06-18)
Am I missing something?
Here there's the correction:
pub trait Directory<P: Person> {
type Per : Person = P;
fn get_person(&self) -> Self::Per;
}
The type Per in Directory can be redefined in trait implementations. The compiler doesn't know if Self::Per (which is the re-defined Per in the implementation) implements the trait Person, so you have to bound it to implement Person.
Here’s the correct code:
pub trait Person {}
pub trait Directory {
type Person: Person;
fn get_person(&self) -> Self::Person;
}
pub trait Catalog {
type Dir: Directory;
fn get_directory(&self) -> Self::Dir;
}
fn do_something<C: Catalog>(catalog: C) {
let directory = catalog.get_directory();
let person = directory.get_person();
do_something_with_person(person);
}
fn do_something_with_person<P: Person>(p: P) {}
<P: Person> is generics syntax. Associated type definitions do not use generic syntax.
Go for the full name in general; don’t abbreviate it Per, leave it Person. It’s always qualified (Directory::Person, C::Person, &c.), so there’s no ambiguity. (Dir is an acknowledged short form of Directory, so there I guess either would be acceptable. I’d probably tend to go with Directory, however.)
There’s no need to have the associated type Person specified on Catalog, either; Self::Dir::Person will do.

Resources