A lib.rs should be able to contain fn self() {}.
e.g.
// lib.rs
fn self<T>() -> T {
Default::default()
}
usage (rust 2018):
use default;
let foo: u32 = default();
A lib.rs should be able to contain fn self() {}.
e.g.
// lib.rs
fn self<T>() -> T {
Default::default()
}
usage (rust 2018):
use default;
let foo: u32 = default();
ā¦and what would fn self() { /* ... */ } do exactly, other than defining a function named self to call?
the module/crate would become a function
Why would that be better than this?
use default::default;
let foo: u32 = default();
It avoids the stutter, which is advised against in the Rust API guidelines.
(I am mostly neutral on this.)
Would you still be able to have other items in a module that declares a self item? Is this self item restricted to being a fn, or can it be any item?
You could just as easily avoid stutter by using a different module name. Contrast this with the fact that a similar feature does not exist for crates, so having a crate with a same-named function in it naturally stutters. (A connect crate with a connect fn inside it would not be a totally wacky thing, but it would still stutter.)
self or Self, and it ends all other items (unless we plan on adding Lua-like metatable-like stuff and fn self is just another special item).
e.g. these are okay:
// foo.rs
fn self(h: usize) -> usize {
}
// bar.rs
struct Self {
}
impl Self {
}
these I donāt like:
struct Foo {}
impl Foo {
fn self() -> Foo {
Foo{}
}
}
// this wouldn't compile (because it conflicts) but this is what a tuple struct would "desugar" to, sort of:
struct Bar(usize);
impl Bar {
fn self(x: usize) -> Bar {
Bar { 0: x }
}
}
from all of these struct Self is the most flexible, as it can have consts and types and fns and stuff. but idk if I like being able to overload things like this. I really just want to get rid of the useless path.
I believe that this is intended to work for crates. (Note that Soni refers to lib.rs in the OP.) I believe this came up due to the discussion around making a Default::default free fn and the new default crate which exposes a single symbol, fn default<T: Default>() -> T.
@Soni, it would help if you list this context when you make a post. It really helps to be explicit and explain the details rather than rely on people to ask for required details to an underspecified, overly general proposal.
thereās a thing youāre supposed to do to set context on this software, but idk how to use it. sorry.
the mention of default shouldāve been a hint. do ppl not read code blocks?
This is the internet. Paste a link.
Not everyone reads every single thread on the forum. Someone might have been linked to this thread from somewhere else. They might have slept since then and forgotten about it.
Also, you gain nothing by using "hints", except potentially driving people away. You're supposed to justify your proposal, not make other people do that research for you.
I don't know if you intended it, but this comes across as phenomenally rude and dismissive. It implies that anyone who doesn't immediately recognise what you're talking about is illiterate and/or stupid.
I saw the lib.rs, but for some reason my brain wanted to interpret it as mod.rs. I still donāt think stutter is problematic enough to drive language changes. Stutter can already be eliminated by convention, and it can be tolerated otherwise. Iād rather it first be linted against if there were a serious problem with it.
Just to clarify: What do you mean by stutter?
The part of the source code that explicitly declares the function?
Or more something along the lines of self::self()?
@Soni It would be helpful to you and everyone else if you refrained from language like āthis I like, but I donāt like thatā when trying to convince others to implement a feature in a programming language.
The problem is that not only is liking something highly subjective, it is a horrendous metric for features: it accounts neither for costs (e.g. the featureās complexity, ecosystem-wide learning costs, limits imposed on the language by the new feature) nor its potential benefits (what is gained, if anything, by adding the feature?)
Putting your feature proposal into cost/benefit terms, I see the following:
*Indirect consequences are important. To see why, consider the example of OO-style inheritance. Itās mostly used to share implementation, which is a direct consequence. An indirect consequence is that that implementation sharing leads to code that is hard to change and maintain, but youāre only confronted by those costs after a while when youāre already suffering the consequences to a fair degree, which makes it an insidious feature. That in turn is one of the major reasons why newer languages donāt add the feature anymore when they can avoid it.
This is already possible to emulate in any position other than crate-root:
pub fn foo() { ... }
pub mod foo { ... }
or if you need access to module internals
pub use self::foo::this;
pub mod foo {
pub(crate) fn this() { ... }
pub fn bar();
}
Using the keyword self for this is problematic with what it means in use context, e.g. if the previous example was in the crate baz then
use baz::foo::self;
fn main() {
foo();
}
would not work, self in use context only imports from the module namespace.
Personally I really like this pattern of merged module/value namespaces, Iāve used it in a crate to provide function scoped errors, bs58::decode(foo).into_vec(): Result<_, bs58::decode::DecodeError> (heh, just noticed that even though Iām using this pattern I stuttered when creating it, I should fix that in the next breaking change). If a crate was basically a single function then I would like to make the crate-root itself that function in the value namespace.
Since there is very limited applicability, I wouldnāt see any reason to have a keyword for this. An alternative would be to just have an attribute that can be applied to a single function at the crate-root
#[hoist_to_be_crate_root_in_public_value_namespace]
fn foo() { ... }
But, Iām not sold that itās useful in enough cases to be worth implementing.
To add to this, I do read every single thread on the forum, and I did immediately recall the default() thread when I read the first post of this one, but I still didn't understand the first post. It simply didn't explain why using self in this way would cause the default:: to magically go away somewhere else in your code.
@Soni In general, I've never been able to tell what you were suggesting from any of your many threads' opening posts. You really need to provide some kind of explanation of what it is you're actually proposing, rather than expecting all of us to read your mind and fill in 90% of the post for you, or play a game of 20 questions to get you to tell us the rest of it (which so far is what always happens).
Stutter is when you use the ānamespaceā in the code such as fmt::Result
Thatās not my understanding of stutter, Iāve always known it as when you use an items parent namespace in the items name, i.e. fmt::FmtResult would be stutter, but fmt::Result is not.
Iām trying to turn the namespace/path into the function.
There would be no need to use foo::bar::self because self isnāt a function name, itās a special syntax that turns foo::bar (also known as self) into a function.
This is useful if:
default crateIt's not about whether there's a need, it's about whether confusion is likely to result. I would find it confusing that I could use the self keyword to declare the "self" function but not import it.
I don't disagree with any of your pros, but I do think they are not strong enough to make the feature worthwhile, in order:
struct Foo { ... } #[allow(some_casing_lint)] fn Foo(...) { ... })You can always use foo::bar::self but itās using bar, just like fn self(){} refers to bar.
And you can do this with mod foo as well as crates.