Mixins / mixing modules and files [duplicate] - module

I have a crate that has lots of code, so I've split it into multiple files/modules. However, some modules have internal unsafe stuff (e.g. raw pointers) that I need to make public to the different modules, but I don't want to expose to users of my crate. How can I do that?
The only way I can think of is to actually have my crate just be one big module, but then there's no way to split it into different files, other than this solution which seems a bit hacky.
Normally when I come up against a real world problem that the simple examples in the Rust docs don't adequately explain I just copy a popular real world crate, e.g. git2-rs, but that just seems to effectively make everything public, including the raw pointers.

In order for an item to be exported from a library crate, there must be at least one path leading to it in which every component is public. This means that all you need to make an item public within your crate but not exported from the crate (I'll call this "internal" from now on, to mimic C# terminology) is to put it in a private module under the crate root.
However, that solution is quite restrictive. What if you'd like to have a module with exported functions and internal functions? In order to export some functions, we need to make the module public, and that mean all public items in that module will be exported as well.
Since Rust 1.18, there's a solution adapted to this kind of scenario: pub(restricted). This feature lets you specify "how public" an item should be. The syntax is pretty flexible (you can make an item visible to a particular module tree instead of the whole crate), but if you want to keep it simple, pub(crate) will make an item accessible anywhere within the crate, but not to other crates (equivalent to internal in C#).
For example, suppose we'd like to have a module util in which foo is exported (as mycrate::util::foo), bar is internal and baz is private to the module. The code might look like this:
pub mod util {
pub fn foo() {
unimplemented!()
}
pub(crate) fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
If you're stuck on pre-1.18 Rust, there's a workaround, but it's a bit clunky. It involves defining all your items in private modules, and reexporting only those that you want to make public (with pub use) in public modules that only contain reexports. Here's what the example above would look like:
pub mod util {
pub use util_impl::foo;
}
mod util_impl {
pub fn foo() {
unimplemented!()
}
pub fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
Not only is this not easy to read and understand, it doesn't cover all situations where pub can be used. For example, how would you make some fields of an exported struct accessible in other modules in the same crate without also exporting them? The only option would be to expose a wrapper with a single private field whose type is the struct that has public fields; that works fine if you want to hide all fields from other crates, but not if you want to expose some fields and make some other fields internal in the same struct.

Related

How to hide sibling modules from each other in Rust?

I have a Rust module breakfast containing two sub modules egg and bacon. The breakfast module must know about egg and bacon, but the two children do not need to and therefore should not know about each other.
This is what my code looks like now. The breakfast gets made, but unfortunately egg and bacon can access each other.
mod breakfast {
pub fn make_breakfast() -> String {
format!("{} and {}", egg::EGG, bacon::BACON)
}
mod egg {
pub const EGG: &'static str = "egg";
}
mod bacon {
pub const BACON: &'static str = "bacon";
// Oh no! The bacon knows about the egg!
// I want this to be a compile error.
use super::egg::EGG;
}
}
Can I hide the siblings from each other somehow, perhaps by using visibility modifiers or by restructuring the modules? Or is the unneeded visibility something I should accept?
In reality, the modules are in separate files, but I put them in one here to make a clearer example.
This is by design:
Rust's name resolution operates on a global hierarchy of namespaces. Each level in the hierarchy can be thought of as some item. The items are one of those mentioned above, but also include external crates. Declaring or defining a new module can be thought of as inserting a new tree into the hierarchy at the location of the definition. [...]
By default, everything in Rust is private, with two exceptions: Associated items in a pub Trait are public by default; Enum variants in a pub enum are also public by default. When an item is declared as pub, it can be thought of as being accessible to the outside world.
With the notion of an item being either public or private, Rust allows item accesses in two cases:
If an item is public, then it can be accessed externally from some module m if you can access all the item's parent modules from m. You can also potentially be able to name the item through re-exports. [...]
If an item is private, it may be accessed by the current module and its descendants.
For further information on this, please consult the relevant chapter of The Reference

Utils class in Kotlin

In Java, we can create an utilities class like this:
final class Utils {
public static boolean foo() {
return false;
}
}
But how to do this in Kotlin?
I try using functions inside object:
object Utils {
fun foo(): Boolean {
return false
}
}
But when call this method from Java code it need to add INSTANCE. Ex: Utils.INSTANCE.foo().
Then I change to declare it as top-level function (without class or object):
#file:JvmName("Utils")
#file:JvmMultifileClass
fun foo(): Boolean {
return true
}
Then I can call Utils.foo() from Java code. But from Kotlin code I got Unresolved reference compiler error. It only allow be to use foo() function directly (without Utils prefix).
So what is the best approach for declaring utils class in Kotlin?
The last solution you've proposed is actually quite idiomatic in Kotlin - there's no need to scope your function inside anything, top level functions are just fine to use for utilities, in fact, that's what most of the standard library consists of.
You've used the #JvmName annotation the right way too, that's exactly how you're supposed to make these top level functions easily callable for Java users.
Note that you only need #JvmMultifileClass if you are putting your top level functions in different files but still want them to end up grouped in the same class file (again, only for Java users). If you only have one file, or you're giving different names per file, you don't need this annotation.
If for some reason you want the same Utils.foo() syntax in both Java and Kotlin, the solution with an object and then #JvmStatic per method is the way to do that, as already shown by #marianosimone in this answer.
You'd need to use #JvmStatic for that:
In Kotlin:
object Utils {
#JvmStatic
fun foo(): Boolean = true
}
val test = Utils.foo()
In Java:
final boolean test = Utils.foo()
Note that the util class you used in Java was the only way to supply additional functions there, for anything that did not belong to a particular type or object. Using object for that in Kotlin does not make any sense. It isn't a singleton, right?
The second approach you mentioned is rather the way to go for utility functions. Internally such functions get translated to static ones and as you can see they become the static util classes in Java you are searching for, as you can't have standalone functions in Java without a class or enum. In Kotlin itself however they are just functions.
Some even count utility classes to the anti-patterns. Functions on the other hand make totally sense without a class or object whose name hasn't so much meaning anyway.

Private inner module returning private item gives "private type in public interface" error

In the below example, the module outer has a private type Private and a private inner module inner. inner is able to access Private (because child modules can access their parent's private items, even if they are not parked as public).
inner defines a function not_really_public_interface(). While it is marked as public, it is really only available to outer because inner itself is not public.
outer.rs
struct Private;
mod inner {
use super::Private;
pub fn not_really_public_interface() -> Private {
Private
}
}
This compiles without any problems.
outer should be able to use inner::not_really_public_interface() to obtain Private, as long as it makes sure not to export it. So let's do that:
pub fn main() {
let _ = self::inner::not_really_public_interface();
}
Right?
stderr
error[E0446]: private type `Private` in public interface
--> src/outer.rs:4:3
|
4 | / pub fn not_really_public_interface() -> Private {
5 | | Private
6 | | }
| |___^ can't leak private type
Wat. This is counter-intuitive to me for several reasons:
The former code produces no error even though it defines a function with an interface Rust considers to "leak". The error only occurs when the outer attempt to use this function.
The only place inner could possibly "leak" Private is to the module that defined it.
So my questions are:
What exactly is going on here that causes Rust to conclude that any part of this interface leaks? It seems like it treats Private as if it were defined in inner.
Is there a context in which this makes perfect sense? My first thought was that this was a bug in the compiler or oversight in the privacy design, but I doubt that's the case.
Is there a way to work around this without creating another module? I believe I can create a wrapper module and then just make Private public within outer and inner, but I'd prefer not to do that.
The function not_really_public_interface is public so it could be used by any other module. But the Private struct can only be accessed by your root and inner modules.
The leak would occur if another module imported not_really_public_interface. Rust is complaining that this could happen because it reports errors locally, rather than taking a "whole world" view across all usages in all modules and crates. Ultimately, this approach is more predictable for humans to reason about and faster for the machine.
Rust lets you control the visibility more precisely though. If you tell it that the function is only available to the module one level up (the super module) then it knows there is no possibility of a leak:
mod inner {
use super::Private;
pub(super) fn not_really_public_interface() -> Private { Private }
}
You could also use crate instead of super, to mean any module in the same crate. Or, if the super module had a name, e.g. my_mod, you could use pub(in ::my_mod) to target it specifically.

How do I make an Rust item public within a crate, but private outside it?

I have a crate that has lots of code, so I've split it into multiple files/modules. However, some modules have internal unsafe stuff (e.g. raw pointers) that I need to make public to the different modules, but I don't want to expose to users of my crate. How can I do that?
The only way I can think of is to actually have my crate just be one big module, but then there's no way to split it into different files, other than this solution which seems a bit hacky.
Normally when I come up against a real world problem that the simple examples in the Rust docs don't adequately explain I just copy a popular real world crate, e.g. git2-rs, but that just seems to effectively make everything public, including the raw pointers.
In order for an item to be exported from a library crate, there must be at least one path leading to it in which every component is public. This means that all you need to make an item public within your crate but not exported from the crate (I'll call this "internal" from now on, to mimic C# terminology) is to put it in a private module under the crate root.
However, that solution is quite restrictive. What if you'd like to have a module with exported functions and internal functions? In order to export some functions, we need to make the module public, and that mean all public items in that module will be exported as well.
Since Rust 1.18, there's a solution adapted to this kind of scenario: pub(restricted). This feature lets you specify "how public" an item should be. The syntax is pretty flexible (you can make an item visible to a particular module tree instead of the whole crate), but if you want to keep it simple, pub(crate) will make an item accessible anywhere within the crate, but not to other crates (equivalent to internal in C#).
For example, suppose we'd like to have a module util in which foo is exported (as mycrate::util::foo), bar is internal and baz is private to the module. The code might look like this:
pub mod util {
pub fn foo() {
unimplemented!()
}
pub(crate) fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
If you're stuck on pre-1.18 Rust, there's a workaround, but it's a bit clunky. It involves defining all your items in private modules, and reexporting only those that you want to make public (with pub use) in public modules that only contain reexports. Here's what the example above would look like:
pub mod util {
pub use util_impl::foo;
}
mod util_impl {
pub fn foo() {
unimplemented!()
}
pub fn bar() {
unimplemented!()
}
fn baz() {
unimplemented!()
}
}
Not only is this not easy to read and understand, it doesn't cover all situations where pub can be used. For example, how would you make some fields of an exported struct accessible in other modules in the same crate without also exporting them? The only option would be to expose a wrapper with a single private field whose type is the struct that has public fields; that works fine if you want to hide all fields from other crates, but not if you want to expose some fields and make some other fields internal in the same struct.

How do I prevent a function from being imported from my module?

I'm looking for something like private attribute working not with class members, but with module entities. Functions, classes, enumerators etc.
For instance, in Erlang there is an export attribute, which goes like this: -export([fun1, fun2]), meaning only fun1 and fun2 of all the functions in the module would be exported. In D everything seems to be exported by default, which is ok, but is there a way to prevent something specific from that?
In the module being imported, you can mark anything private to keep it from being accessible from other modules. private works the same way on module level entities as it does on class members - inaccessible outside the module, usable inside the module. However, currently it is still visible, so it can create silly errors like "private function foo from module A conflicts with function foo from module B", forcing you to disambiguate the name. (I, and several others, are hoping to get this changed at some point, since it obviously shouldn't be a problem!)
In the module doing the importing, you can't say "import all except", but you can import a list of specific names without importing others:
import std.stdio : File, writefln;
void main() {
File f; // cool
writefln("hello"); // cool
writeln("hey"); // "Error: 'writeln' is not defined" - the selective import didn't pull this name at all
}