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

Tracking Issue for RFC 213: Default Type Parameter Fallback #27336

Closed
jroesch opened this issue Jul 27, 2015 · 77 comments · Fixed by #127655
Closed

Tracking Issue for RFC 213: Default Type Parameter Fallback #27336

jroesch opened this issue Jul 27, 2015 · 77 comments · Fixed by #127655
Assignees
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-default_type_parameter_fallback `#![feature(default_type_parameter_fallback)]` T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@jroesch
Copy link
Member

jroesch commented Jul 27, 2015

2024-07-15: This feature (default_type_parameter_fallback) is slated for removal, but that is currently blocked on too many crater regressions.


EDIT: this issue has been stalled on disagreements about how to handle a nasty problem found during implementation. See the internals thread where this was detailed and discussed.


This is a tracking issue for RFC 213.

The initial implementation of this feature has landed.

cc @nikomatsakis

@jroesch jroesch self-assigned this Jul 27, 2015
@steveklabnik steveklabnik added the B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. label Jul 29, 2015
@alexcrichton alexcrichton added the T-lang Relevant to the language team, which will review and decide on the PR/issue. label Aug 11, 2015
@nikomatsakis nikomatsakis added the B-unstable Blocker: Implemented in the nightly compiler and unstable. label Aug 14, 2015
@bluss
Copy link
Member

bluss commented Nov 20, 2015

What is the status of this?

@pnkfelix
Copy link
Member

pnkfelix commented Dec 1, 2015

@bluss it is still feature-gated, AFAICT. See e.g. the discussion on PR #26870 , or just look at this playpen

I am not sure what the planned schedule is for unfeature-gating it.

nominating for discussion.

@mahkoh
Copy link
Contributor

mahkoh commented Dec 11, 2015

This doesn't seem to be working properly.

#![crate_type = "lib"]
#![feature(default_type_parameter_fallback)]

trait A<T = Self> {
    fn a(t: &T) -> Self;
}

trait B<T = Self> {
    fn b(&self) -> T;
}

impl<U, T = U> B<T> for U
    where T: A<U>
{
    fn b(&self) -> T {
        T::a(self)
    }
}

struct X(u8);

impl A for X {
    fn a(x: &X) -> X {
        X(x.0)
    }
}

fn f(x: &X) {
    x.b(); // ok
}

fn g(x: &X) {
    let x = x.b();
    x.0; // error: the type of this value must be known in this context
}

@jroesch
Copy link
Member Author

jroesch commented Dec 15, 2015

@mahkoh there is a necessary patch that hasn't gotten rebased since I stopped my summer internship. I've been unfortunately busy with real life stuff, looks like @nikomatsakis has plans for landing a slightly different version according to a recent post of his on the corresponding documentation issue for this feature.

@bluss
Copy link
Member

bluss commented Feb 22, 2016

@nikomatsakis I know the lang team didn't see any future in this feature, will you put that on record in the issue 😄?

One example where this feature seems to be the only way out is the following concrete example of API evolution in libstd.

Option<T> implements PartialEq today, but we would like to extend it to PartialEq<Option<U>> where T: PartialEq<U>. It appears this feature can solve the type inference regressions that would otherwise occur (and might block us from doing this oft-requested improvement of Option).

@nikomatsakis
Copy link
Contributor

@bluss I HAVE been dubious of this feature, but I'm been slowly reconsidering. @aturon is supposed to be doing some exploration of this whole space and writing up some detailed thoughts. I actually started rebasing @jroesch's dead branch to implement the desired semantics and making some progress there too, but I've been distracted.

One advantage of finishing up the impl is that it would let us experiment with extensions like the one you describe to see how backwards compatible they truly are -- one problem with fallback is that it is not ACTUALLY backwards compatible, because of the possibility of competing incompatible fallbacks.

@nikomatsakis
Copy link
Contributor

That said I still have my doubts :)

@nikomatsakis
Copy link
Contributor

Another example where this could be useful -- basically the same example as petgraph -- is adding allocators to collections in some smooth way.

@durka
Copy link
Contributor

durka commented Feb 24, 2016

What are the drawbacks to turning this on? It seems to mainly make things compile that otherwise cannot infer enough type information.

@abonander
Copy link
Contributor

I have a pretty good use for this too. It's basically what @bluss mentioned, adding new types to an impl while avoiding breaking inference on existing usage.

@withoutboats
Copy link
Contributor

Is the only issue with this the interaction with numeric fallback? I like default type parameters a lot. I often use them when I parameterize a type which has only one production instantiation, for mocking and to enforce bondaries. Its inconsistent and for me unpleasant that defaults don't work for the type parameters of functions.

yodaldevoid added a commit to yodaldevoid/embassy that referenced this issue Dec 9, 2022
It would be nice if a default value could be used so old code would
mostly just work, but defaults are not used while determining types so
adding a default does nothing here.

It would also be nice if we could calculate the number of interfaces
needed at compile time, but I'll leave that as an exercise for later.

rust-lang/rust#95486
rust-lang/rust#99727
rust-lang/rust#27336
yodaldevoid added a commit to yodaldevoid/embassy that referenced this issue Dec 9, 2022
It would be nice if a default value could be used so old code would
mostly just work, but defaults are not used while determining types so
adding a default does nothing here.

It would also be nice if we could calculate the number of interfaces
needed at compile time, but I'll leave that as an exercise for later.

rust-lang/rust#95486
rust-lang/rust#99727
rust-lang/rust#27336
yodaldevoid added a commit to yodaldevoid/embassy that referenced this issue Dec 14, 2022
It would be nice if a default value could be used so old code would
mostly just work, but defaults are not used while determining types so
adding a default does nothing here.

It would also be nice if we could calculate the number of interfaces
needed at compile time, but I'll leave that as an exercise for later.

rust-lang/rust#95486
rust-lang/rust#99727
rust-lang/rust#27336
@QuineDot
Copy link

I did believe that T:: and <T>:: were equivalent, but it's not the case.

What's the difference between T:: and <T>::? Can somebody explain to me why this hack actually works?

Types in part of a (path) expression, like T::, use inference for all elided type parameters -- including defaulted ones -- and do not fallback to the defaulted type when running into ambiguity. That's pretty much what this RFC was about. So these are equivalent and cannot currently fallback to the defaulted type (and thus fail to compile):

    let _ = Foo::Baz;
    let _ = Foo::<_>::Baz;

Where as in type ascription location, you can't elide non-defaulted parameters, but if you elide defaulted parameters they take on the default value. (Then the inferred type parameter in the expression can be resolved from the ascription.) So these are all the same and compile:

    let _: Foo = Foo::Baz;
    let _: Foo<String> = Foo::Baz;
    let _: Foo = Foo::<_>::Baz;
    let _: Foo<String> = Foo::<_>::Baz;

And then we have <T>:: in an expression. The T in <T> is always a type -- on its own inside the <>, T is not part of an expression. Similar to type ascription, you can't elide non-defaulted parameters, but if you elide default parameters they take on the default value. So these are the same:

    let _ = <Foo>::Baz;
    let _ = <Foo<String>>::Baz;

<T> was introduced in RFC 0132, which also says that Foo::<_>::... is now equivalent to <Foo<_>>::.... And sure enough, these don't compile either, as the inference still does not fallback to defaults.

    let _ = <Foo<_>>::Baz;
    let _: Foo<_> = Foo::Baz;

Summary

  • In an expression position (where you need turbofish)
    • You can elide parameters whether they are defaulted or not
    • Elided parameters, with or without a default, will become fresh inference variables (_)
      • Which do not fallback to parameter defaults
  • In a type position (where you don't need turbofish)
    • You cannot elide non-default parameters
    • Elided default parameters will use the default, not inference
    • "Type position" includes type ascription and <T>

@peter-lyons-kehl
Copy link
Contributor

peter-lyons-kehl commented Jan 20, 2023

  1. Is this still a tracking issue for https://github.com/rust-lang/rfcs/blob/master/text/0213-defaulted-type-params.md (as referenced from that RFC, and from https://doc.rust-lang.org/nightly/unstable-book/language-features/default-type-parameter-fallback.html)?

    If so/As such, shouldn't this issue (or whatever tracking issue) be open (while the feature is, at least somewhat, on nightly) - regardless of unclear future for it?

  2. Is this (or any other nightly feature, or another RFC) supposed to apply to either:

  • return types of (non-associated) functions, where the return type is not related to any of the arguments (or the function doesn't have any arguments at all)? (I can't see anything else relevant in the Unstable Book, nor at https://rust-lang.github.io/rfcs).
  • return types of associated functions, where the return type can be (humanly) inferred from the default type parameter(s) of the struct (or even a trait, if possible)?

    And if those are not considered/planned/tracked anywhere, how likely would they be to implement, please?

    The following two examples fail with current nightly: cannot infer type of the type parameter A... or type annotations needed, respectively:
#![feature(default_type_parameter_fallback)]

pub fn empty_vec<A=u32>() -> Vec<A> {
    Vec::new()
}

pub fn use_empty_vec() {
    empty_vec();
}
#![feature(default_type_parameter_fallback)]

use core::marker::PhantomData;

pub struct WithTypeDefault<T = ()> {
    field: PhantomData<T>
}

impl <T> WithTypeDefault<T> {
    pub fn to_t(&self) -> T {
        loop {}
    }
}

pub fn use_to_t() {
    let with_type_default = WithTypeDefault {field: PhantomData {} };
    let to_t = with_type_default.to_t();
}

@traviscross

This comment was marked as outdated.

@peter-lyons-kehl
Copy link
Contributor

peter-lyons-kehl commented Nov 20, 2023

Someone with access, or @Gankra or @jroesch, could you update the very first comment (issue description) to reflect the following, so as to save readers' time, please.

  1. The current "EDIT" part (updated in July 2019) is increasing confusion, because
  • in one paragraph it mentions two parts:
    -- "stalled on disagreements... problem found during implementation" and
    -- it links to See the internals thread where this was detailed and discussed.
  • (due to GitHub's design) the reader doesn't see right away that the "EDIT" part was added in 2019, two years after that (referred) internals thread was closed.

Unfortunately, that internals thread was auto-closed, and the last comment (from September 2015) says that "the lang subteam" has had a "consensus". So, it doesn't explain the problem mentioned in the "EDIT" in 2019.

As is, the "EDIT" paragraph easily confuses readers to search for the problem in that internals thread. Please split into two paragraphs, or add some wording to make the separation clear.

  1. Update the RFC link not to contain the timestamp, in case it gets updated. (According to its commit messages, it has had only typo changes since that timestamp). https://github.com/rust-lang/rfcs/blob/master/text/0213-defaulted-type-params.md

  2. Consider linking the description to Default Type Parameter Fallback: Revival #46206.

Curious: Was the problem found during implementation only when there is a conflict between the user-supplied default type and an inferred type? Because I have a huge piece of work (for alloc) that would not have such a conflict (or, in internal or nightly code only). And many people here report this useful, too.

@RalfJung
Copy link
Member

There's still a feature gate, default_type_parameter_fallback, pointing to this issue. @rust-lang/types should the issue be reopened, the feature gate removed, or the feature gate be changed to point to a different issue?

@lcnr
Copy link
Contributor

lcnr commented Jul 15, 2024

I think we should completely remove the feature gate. It's currently only partially implemented and requires some significant design work before we re-add it afaict.

@nikomatsakis
Copy link
Contributor

nikomatsakis commented Jul 15, 2024 via email

@RalfJung
Copy link
Member

Sadly that's not really possible currently, typemap uses this feature...

@RalfJung
Copy link
Member

I will reopen the issue then -- as long as the feature gate exists, the tracking issue it points to should remain open.

@RalfJung RalfJung reopened this Jul 15, 2024
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 4, 2024
…t, r=compiler-errors

turn `invalid_type_param_default` into a `FutureReleaseErrorReportInDeps`

`@rust-lang/types` I assume the plan is still to disallow this? It has been a future-compat lint for a long time, seems ripe to go for hard error.

However, turns out that outright removing it right now would lead to [tons of crater regressions](rust-lang#127655 (comment)), so for now this PR just makes this future-compat lint show up in cargo's reports, so people are warned when they use a dependency that is affected by this.

Fixes rust-lang#27336 by removing the feature gate (so there's no way to silence the lint even on nightly)
CC rust-lang#36887
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 4, 2024
…t, r=compiler-errors

turn `invalid_type_param_default` into a `FutureReleaseErrorReportInDeps`

``@rust-lang/types`` I assume the plan is still to disallow this? It has been a future-compat lint for a long time, seems ripe to go for hard error.

However, turns out that outright removing it right now would lead to [tons of crater regressions](rust-lang#127655 (comment)), so for now this PR just makes this future-compat lint show up in cargo's reports, so people are warned when they use a dependency that is affected by this.

Fixes rust-lang#27336 by removing the feature gate (so there's no way to silence the lint even on nightly)
CC rust-lang#36887
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 4, 2024
…t, r=compiler-errors

turn `invalid_type_param_default` into a `FutureReleaseErrorReportInDeps`

```@rust-lang/types``` I assume the plan is still to disallow this? It has been a future-compat lint for a long time, seems ripe to go for hard error.

However, turns out that outright removing it right now would lead to [tons of crater regressions](rust-lang#127655 (comment)), so for now this PR just makes this future-compat lint show up in cargo's reports, so people are warned when they use a dependency that is affected by this.

Fixes rust-lang#27336 by removing the feature gate (so there's no way to silence the lint even on nightly)
CC rust-lang#36887
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this issue Aug 5, 2024
…t, r=compiler-errors

turn `invalid_type_param_default` into a `FutureReleaseErrorReportInDeps`

````@rust-lang/types```` I assume the plan is still to disallow this? It has been a future-compat lint for a long time, seems ripe to go for hard error.

However, turns out that outright removing it right now would lead to [tons of crater regressions](rust-lang#127655 (comment)), so for now this PR just makes this future-compat lint show up in cargo's reports, so people are warned when they use a dependency that is affected by this.

Fixes rust-lang#27336 by removing the feature gate (so there's no way to silence the lint even on nightly)
CC rust-lang#36887
@bors bors closed this as completed in cc61dc8 Aug 5, 2024
rust-timer added a commit to rust-lang-ci/rust that referenced this issue Aug 5, 2024
Rollup merge of rust-lang#127655 - RalfJung:invalid_type_param_default, r=compiler-errors

turn `invalid_type_param_default` into a `FutureReleaseErrorReportInDeps`

`````@rust-lang/types````` I assume the plan is still to disallow this? It has been a future-compat lint for a long time, seems ripe to go for hard error.

However, turns out that outright removing it right now would lead to [tons of crater regressions](rust-lang#127655 (comment)), so for now this PR just makes this future-compat lint show up in cargo's reports, so people are warned when they use a dependency that is affected by this.

Fixes rust-lang#27336 by removing the feature gate (so there's no way to silence the lint even on nightly)
CC rust-lang#36887
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. B-RFC-implemented Blocker: Approved by a merged RFC and implemented. B-unstable Blocker: Implemented in the nightly compiler and unstable. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-default_type_parameter_fallback `#![feature(default_type_parameter_fallback)]` T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.