-
Notifications
You must be signed in to change notification settings - Fork 13k
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
Implement default type parameters in generics. #11217
Conversation
let _ = S::<'a,int>::new::<f64>(1, 1.0); //~ ERROR expected 0 lifetime parameter(s) | ||
let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this path has 1 type parameter, but 0 type parameters were supplied | ||
let _: S2 = Trait::new::<int,f64>(1, 1.0); //~ ERROR the trait referenced by this needs has 1 type parameter, but 0 type parameters were supplied |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, meant to replace the 'has' (which I changed to 'needs' in the typeck code).
This clearly needs discussion at the meeting (which is delayed until the new year because of holidays) but I am tentatively in favor because of custom allocators. However, we need to decide how this contrasts with:
Right now this won't work because you won't be able to write |
} | ||
|
||
fn main() { | ||
Vec::<int, Heap, bool>::new(); //~ ERROR the impl referenced by this path needs at most 2 type parameters, but 3 type parameters were supplied |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line won't pass make tidy
's length checker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it will (just checked).
I believe tests are allowed to exceed the normal limit because of placement constraints for those comments.
Yay! (This would also allow, e.g., customising the hash used by the hashmap, which would allow us to resolve issues like #10586 in a nice way.) As you said on IRC, this needs rpass tests. Maybe a basic test like the following, along with some more complicated ones: struct Foo<A=(int, char)> {
a: A
}
fn default_foo(x: Foo) {
let (_i, _c): (int, char) = x.a;
x.bar();
}
impl Foo {
fn bar(&self) {
let (_i, _c): (int, char) = self.a;
}
}
fn main() {
default_foo(Foo { a: (1, 'a') })
} |
Would it be palatable to add this, but keep it behind a |
I have added this to the next meeting agenda (not that this is required to wait until then). |
Let's discuss at next meeting. |
@eddyb I have the same question as pcwalton: aside from ergonomic issues stemming from current deficiencies of the language, why are typedefs not an adequate solution here? In a sense it's even cleaner because it doesn't require the generic implementation to have any knowledge of the default. |
It's not just the ergonomics of calling things on typedefs, it means we'd need a pile of items & typedefs for every generic data structure everywhere (lots of struct HashMapHashAlloc<K, V, Hash, Alloc> {
...
}
type HashMapHash<K, V, Hash> = HashMapHashAlloc<K, V, Hash, LibcAllocator>;
type HashMap<K, V> = HashMapHashAlloc<K, V, SipHash, LibcAllocator>; |
|
Maybe; I was just going with our current scheme where the hash uses
(Just to be clear, I left that one out because, on first thought, it seemed like it would be the rarest; this may or may not be true. I wasn't omitting it to attempt to paper over a deficiency.)
Does HKT require partial application only at the end of a type? This seems rather unlikely to me. Certainly writing That said, the best other scheme I can think of right now is something like |
Indeed, but this is only an issue at the syntax level.
Essentially yes (or rather only at the front, leaving free the parameters at the end, but that's what you meant), otherwise you admit type-level lambdas which don't seem like a good idea. |
cc me |
I am tentatively in favor of this. There is a negative interaction with Higher-Kinded Types: if effectively requires us to make partially applied types explicitly indicated (e.g., Particularly as there is no formal write up, I'd like to review the PR before it gets merged to make sure I understand all the consequences. |
Let me amend the last statement: s/Particularly as there is no formal write up/Particularly as I haven't seen a formal write up/ -- not sure if there is something I haven't seen? (I'm quite behind in bugmail etc) |
I'm not yet convinced this buys us all that much over just telling people to use struct HashMapHashAlloc<K, V, Hash, Alloc> {
...
}
type HashMapHash<K, V, Hash> = HashMapHashAlloc<K, V, Hash, LibcAllocator>;
type HashMap<K, V> = HashMapHash<K, V, SipHash>; |
oh, I see, @pcwalton pointed out why this workaround is currently deficient in his opening comment. Yes, we should talk about whether to enable calling methods through typedefs. |
Requiring partial application to be explicit might be alright. But this is ignoring the subtler issue: if you want to be able to write a |
This is fine per the meeting. |
We did decide though that we would like to put this behind a feature gate (it may be right now, sorry I haven't looked to closely). The feature gate is a little tough in that it needs to gate the definition of types with default type parameters, but it should also gate usage of the default type parameters. For example: struct A<Foo = Bar>; // gated
let _: A = ... ; // not gated
let _: A<MyType> = ... ; // gated |
@alexcrichton shouldn't the latter two be the other way around? I would understand "using" a default type argument to mean omitting it and having the compiler supply the default. |
In theory, we would want to change |
I guess either choice is fine as long it's consistent. |
No description provided.