Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for use Trait::func #3591

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open

Conversation

obsgolem
Copy link

@obsgolem obsgolem commented Mar 19, 2024

Rendered

This feature fully supplants rust-lang/rust#73001, allowing you to do things like:

use Default::default;

struct S {
    a: HashMap<i32, i32>,
}

impl S {
    fn new() -> S {
        S {
            a: default()
        }
    }
}

and more.

This is my first RFC, please forgive any missteps I make in the process.

Partially completes #1995.

@ehuss ehuss added the T-lang Relevant to the language team, which will review and decide on the RFC. label Mar 20, 2024
@Evian-Zhang
Copy link

From The Rust Programming Language section 7.4:

Creating Idiomatic use Paths

Although both Listing 7-11 and 7-13 accomplish the same task, Listing 7-11 is the idiomatic way to bring a function into scope with use. Bringing the function’s parent module into scope with use means we have to specify the parent module when calling the function. Specifying the parent module when calling the function makes it clear that the function isn’t locally defined while still minimizing repetition of the full path.

We have been encouraged for a long time to always import the parent module when calling the function to distinguish locally defined functions and imported functions. However, the syntax sugar suggested in this RFC contradicts to this convention.

I think it is more appropriate to discuss this convention in the RFC to make it more clear how we should use this feature. :)

@crumblingstatue
Copy link

I'd like to reiterate here what I said on #1995

Many libraries define free functions for constructors to mathy types, like vectors.

Some examples:
https://docs.rs/glam/0.24.2/src/glam/f32/vec2.rs.html#12
https://docs.rs/egui/latest/egui/fn.pos2.html

It would be nice if instead of having to create wrapper functions, the user (or the lib author with pub use) could just do use Vec2::new as vec2;

This is some additional motivation that could go into the motivation section. Default::default is hardly the only use case for this.

@crumblingstatue
Copy link

That being said, I noticed that this RFC doesn't talk about importing inherent methods, which I think should be addressed.
If this RFC only proposes importing trait methods, but not inherent methods, then the use cases I mentioned above are nullified.
Why should we only support importing trait methods, but not inherent methods?

@obsgolem
Copy link
Author

I discussed that in the future work section. use Type::method is out of scope for this RFC. The difficulty is impl blocks with arbitrary where clauses.

Copy link
Contributor

@kpreid kpreid left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The RFC text uses the term “method” where it should be using the term “associated function”.

  • An associated function is a function defined in an impl or declared in a trait. (reference)
  • A method is an associated function that has a self parameter (and therefore may be used in .func_name() method-call syntax). (reference)

I recommend that this be corrected to avoid creating confusion. In particular, the central use case of this feature is importing associated functions that are less concise to call because they are not methods, such as Default::default.

text/0000-import-trait-methods.md Outdated Show resolved Hide resolved
text/0000-import-trait-methods.md Outdated Show resolved Hide resolved
@obsgolem obsgolem changed the title Add support for use Trait::method Add support for use Trait::func Mar 31, 2024
@joshtriplett
Copy link
Member

I'm going to go ahead and start the process of seeing if we have consensus on this:

@rfcbot merge

Please do either add support for associated constants inline in the RFC (if it's straightforward to do so) or mention them in future work (if not):

@rfcbot concern associated-constants

@obsgolem
Copy link
Author

Apologies for the delay, wasn't able to work up motivation to work on this again until today. Thanks for the review!

```rust
use Trait::item as m;
```
occurs, a new item `m` is made available in the value namespace of the current module. Any attempts to use this item are treated as using the associated item explicitly qualified. `item` must be either an associated function or an associated constant. As always, the `as` qualifier is optional, in which case the name of the new item is identical with the name of the associated item in the trait. In other words, the example:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, "value namespace" here surprised me. What happens if item is actually an associated type?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item must be either an associated function or an associated constant

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See this discussion for motivation for including associated constants, which wasn't in my first draft.

@scottmcm
Copy link
Member

👍 to the motivation here.

@rfcbot concern what-about-turbofish

One thing I think needs to be addressed in the reference section is what's supposed to happen with generic parameters.

If one has

trait Trait<A> {
    fn method<B>();
}

and does a

use othermod::Trait::method;

What happens? Can you turbofish it? Which generics are there there?

The precedent from enum variants doesn't cover generics on the associated items, so something needs to specified for it.

@obsgolem
Copy link
Author

This can be inferred directly from the desugaring described in the RFC. If the trait has generics, they must be inferrable in order for Trait::method() to work, hence the same is true for the imported version. I can spell that out explicitly if you want.

@obsgolem
Copy link
Author

obsgolem commented Jul 8, 2024

Just wanted to ping this, is there anything I can do to keep this moving?

@joshtriplett joshtriplett added the I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. label Jul 16, 2024
@joshtriplett
Copy link
Member

Nominated for lang discussion.

@GoldsteinE
Copy link

This is currently implemented on nightly as part of fn_delegation (rust-lang/rust#118212): https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=fe2a0b28cf36b474400ae3faa10c5408

#![expect(incomplete_features)]
#![feature(fn_delegation)]

reuse Default::default;

fn type_name_of_val<T>(_: &T) -> &'static str {
    std::any::type_name::<T>()
}

fn main() {
    let x: u32 = default();
    let y = default::<u64>();
    let name = type_name_of_val(&default::<()>);
    dbg!(x, y, name);
}

@tmandry
Copy link
Member

tmandry commented Sep 18, 2024

@rfcbot reviewed

This RFC does not propose the ability to import Type::method where method is contained in an impl block. Such a feature would be a natural extension of this work, and would enable numeric features like that discussed in motivation without the need for the num_traits crate. This feature is not proposed in this RFC since initial investigations revealed that it would be difficult to implement in today's rustc.

I would very much like to see this, though I am okay waiting for a future RFC once the implementation challenges are worked out.

If we add a compatibility mechanism to implement a supertrait method when implementing its subtrait, without having to separately implement the supertrait (such that a new supertrait can be extracted from a trait without breaking compatibility), we would also need to lift the limitation on using a supertrait method via a subtrait.

I would also very much like to see this, but yes it belongs in another RFC. While I would prefer to lift the subtrait/supertrait restriction part of this RFC, it sounds annoying to do so it can wait for the next RFC.

The restriction on importing parent trait associated functions is a consequence of this desugaring, see https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=51bef9ba69ce1fc20248e987bf106bd4 for examples of the errors you get when you try to call parent trait associated functions through a child trait. We will likely want better error messages than this if a user tries to import a parent function.

Those errors are bizarre and I agree we should make them better (and as I said, eventually remove them altogether).

@tmandry
Copy link
Member

tmandry commented Sep 19, 2024

This can be inferred directly from the desugaring described in the RFC. If the trait has generics, they must be inferrable in order for Trait::method() to work, hence the same is true for the imported version. I can spell that out explicitly if you want.

Trying to get outstanding concerns resolved: I think the request by @scottmcm was that it be spelled out in the reference section. I don't see a drawback to including implications like this as subsections, even if they are implied by the earlier text. (The paragraph you have on the restriction on important parent trait functions is an example of this.)

@joshtriplett
Copy link
Member

@rfcbot resolved associated-constants

@tmandry
Copy link
Member

tmandry commented Oct 24, 2024

@obsgolem Would you add some text elaborating on how trait generics work, so we can get the last concern resolved?

@scottmcm
Copy link
Member

The reference seems to still only talk about using inference for the generics on such an imported thing, like

Note that trait generics are handled by this desugaring using type inference.

and

which compiles if and only if T and Self can be inferred from the function call

Is the idea here that something imported like this can only be used inferred, and we block turbofishing it for now?

For use Default::default;, is no turbofishing allowed because there are no generic parameters on either Default nor default? Or is there something that adds a turbofishable generic parameter for the Self type so I can default::<X>()?

For use FromIterator::from_iter;, if I do from_iter::<X>(it), is that turbofishing the generic from FromIterator, the generic from from_iter, or is it an error?

@scottmcm
Copy link
Member

Ok, with the update to say

Generics on Trait are not directly specifiable when a function is called in this way. To call a function with explicit types specified you must use the usual fully qualified syntax.

@rfcbot resolve what-about-turbofish

I do think that people will want to turbofish this in the future, but I'm happy to say that for now they just can't, like we did with APIT, and we can reconsider things later as needed.

@rfcbot rfcbot added the final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. label Oct 30, 2024
@rfcbot
Copy link
Collaborator

rfcbot commented Oct 30, 2024

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot removed the proposed-final-comment-period Currently awaiting signoff of all team members in order to enter the final comment period. label Oct 30, 2024
@rfcbot rfcbot added finished-final-comment-period The final comment period is finished for this RFC. to-announce and removed final-comment-period Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised. labels Nov 9, 2024
@rfcbot
Copy link
Collaborator

rfcbot commented Nov 9, 2024

The final comment period, with a disposition to merge, as per the review above, is now complete.

As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.

This will be merged soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
disposition-merge This RFC is in PFCP or FCP with a disposition to merge it. finished-final-comment-period The final comment period is finished for this RFC. I-lang-nominated Indicates that an issue has been nominated for prioritizing at the next lang team meeting. T-lang Relevant to the language team, which will review and decide on the RFC. to-announce
Projects
None yet
Development

Successfully merging this pull request may close these issues.