Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upTracking issue for experiments around coercions, generics, and Copy type ergonomics #44619
Comments
aturon
added
the
T-lang
label
Sep 15, 2017
This was referenced Sep 15, 2017
aturon
added
E-needs-mentor
WG-compiler-middle
WG-compiler-traits
labels
Sep 17, 2017
Mark-Simulacrum
added
the
C-tracking-issue
label
Sep 18, 2017
kennytm
referenced this issue
Sep 19, 2017
Open
Ergonomics: &String does not implement PartialEq<str> #44695
nikomatsakis
referenced this issue
Sep 21, 2017
Open
Tracking issue: Allow autoderef and autoref in operators (experiment) #44762
nikomatsakis
removed
the
E-needs-mentor
label
Sep 21, 2017
This comment has been minimized.
This comment has been minimized.
|
While trying to generalize a concept in Rocket, I ran into issues when coercions I expected to happen automatically did not. I'll illustrate with examples. In the code below, the trait Handler { }
impl<F> Handler for F where F: Fn(&str) -> &str { }
fn is_handler<H: Handler>(_: H) { }
fn dyn_handler(_: &str) -> &str { "hi" }
is_handler(dyn_handler);On the other hand, none of the fn static_handler(_: &str) -> &'static str { "hi" }
is_handler(static_handler);
is_handler(|_| "hi");
is_handler(|x| x);In each of these cases, however, a manual coercion can be applied that results in the call typechecking: is_handler(static_handler as for<'r> fn(&'r str) -> &'r str);
is_handler((|_| "hi") as for<'r> fn(&'r str) -> &'r str);
is_handler((|x| x) as for<'r> fn(&'r str) -> &'r str);I expected that the coercions applied manually above would be applied automatically by Rust. In particular, I expected the But note that similar coercions are automatically applied when a function trait bound is enjoined without an accompanying fn mk_handler<F: Fn(&str) -> &str>(f: F) -> F { f }
is_handler(mk_handler(|_| "hi"));
is_handler(mk_handler(|x| x));This implies that there already exists machinery to automatically perform these types of coercions in certain situations. I'd like to see these particular automatic coercions be applied during P.S: There are also cases where a manual coercion doesn't result in a typechecked call while an automatic coercion does: // does not typecheck
is_handler((|x: &str| x) as for<'r> fn(&'r str) -> &'r str);
// typechecks
is_handler(mk_handler(|x: &str| x));And cases were neither works where it would likely be expected to: // does not typecheck
is_handler((|x: &str| -> &str { x }) as for<'r> fn(&'r str) -> &'r str);
// does not typecheck
is_handler(mk_handler(|x: &str| -> &str { x })); |
This comment has been minimized.
This comment has been minimized.
|
I am assuming you are talking about this example: is_handler(|_| "hi"); //~ ERROR
is_handler(mk_handler(|_| "hi")); // okThere are no coercions in either of these examples - the second one successfully uses the However, some specific examples are different, non-coercion problems: is_handler((|x: &str| x) as for<'r> fn(&'r str) -> &'r str);That is just #38714, which is being fixed is_handler(mk_handler(|x: &str| -> &str { x }));This also looks like some sort of screwiness, we might look into it. |
This comment has been minimized.
This comment has been minimized.
This appears to be true sometimes and not other times, but either way, my point is that (at least for function types) coercions should be trigged based on the set of pending trait obligations. For an instance of when these coercions do presently trigger, see the example towards the middle of my comment. I've reproduced it below: fn mk_handler<F: Fn(&str) -> &str>(f: F) -> F { f }
is_handler(mk_handler(|_| "hi"));
is_handler(mk_handler(|x| x)); |
This comment has been minimized.
This comment has been minimized.
Actually there are no coercions in any of these examples (except when explicitly triggered via casts), just heuristic HRT inference. |
This comment has been minimized.
This comment has been minimized.
Sorry, you're right; I was indeed referring to inference with respect to the closures. To rephrase, I meant to exhibit that the inferred type for |
erickt
referenced this issue
Nov 6, 2017
Closed
alloc: Add Borrow impls for &String, &mut String, &Vec, and &mut Vec #45808
nikomatsakis
referenced this issue
Feb 27, 2018
Closed
tracking issue for default binding modes in match (RFC 2005, match_default_bindings) #42640
This comment has been minimized.
This comment has been minimized.
|
For my own future searchability: this issue would address (certain cases of) the Eye of Sauron. |
This comment has been minimized.
This comment has been minimized.
H2CO3
commented
Mar 26, 2018
|
I would also be nice to add a lint for autoref, not only auto-deref. Autoref can be dangerous too (when exact addresses matter, e.g. in FFI and memory-mapped I/O) — and for me, "dangerous" is far worse than "degrades performance" as a first approximation. Personally I would never want to use either the autoref or the autoderef feature, and I'd like the compiler to scream at me if it still ever happens by accident. |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
Nov 23, 2018
•
|
interesting issue, my wish is for auto-borrows, (coming from C++ operator behaviour). I'm having to bounce between methods, operators, copy types with a number of conflicting draws (with C++ giving the case I actually want). it's not just that "it's that way in c++" - we had the ability to write anything (unchecked move or borrow) in C; whilst people complain about C++ references, sane operators was actually their driving use case. personally I would hope it's possible to get the best of both worlds perhaps with a As I see it moves or borrows are different preferences based on situations; I've never wanted maths to consume via moves, wheras control structures for threads & inserting items into collections are a clear move use-case. Also without overloading it should be easier to determine what to do from the function name (the compiler does seem to know the alternative in its error messages alot of the time) explicit mutable borrows are ok as you want to see the side effects. Besides that there's an intuition/readability aspect - mixing &'s and +'s hurts alot (and people must likely move back & forth between C++/rust.. I can't afford to throw away my fluency with the former) because you've learned to expect those operators to have certain meaning in positions, when combined like that it just looks like an error (& is associated with bitwise arithmetic or generating addresses when not, + near addresses is associated with pointer arithmetic.. , it's too much ). it was less of a pain to revert to named functions ("a.vadd(&b)"). I would have thought it would be far more sensible all round to keep the expectation of operators the same as C++ and resort to named functions for anything else (e.g. + is sometimes abused for concatenation which has different semantics to arithmetic.. better to use a named function there if you don't want to go the custom-operator route) Also originally I thought this was more about the operators but I realise now (from a previous 'bounce' in my sourcebase) that it's about the lack of auto-borrow generally (autoborrow exists for the receiver and is fine there). you can apply a concept like 'linear interpolation' to some quite weighty objects, but it would be nice to keep the same interface as for vectors.. it's a sliding scale. It creates distress relying on unstated semantics r.e making maths-types 'copy' ("hope the compiler will turn it into a reference..") which also narrows the use cases. (having delved into AI i want to keep my graphics maths general enough for n-d vector, which don't want to be 'copy'). I want to just implement operators for borrows, and have those work, rather than have to implement &T op T T op &T etc etc. Since I discovered Rust 5 years ago I originally went for named methods for maths , because the borrows were less obtrusive (and not all the overload permutations could be expressed) ; I was happy to wait and see how things evolved but unfortunately I think operators went the wrong way.. but it should be possible to fix with a backwards compatible preference |
This comment has been minimized.
This comment has been minimized.
dobkeratops
commented
Nov 23, 2018
|
to throw an idea out there, |
aturon commentedSep 15, 2017
•
edited by nikomatsakis
This issue tracks experimental work, overseen by the lang team, on several interrelated topics:
Copytypes and references (i.e. "imagine never having to write&0orlet z = &u * &(&(&u.square() + &(&A * &u)) + &one);again)Copytypes.Clone.None of these bullet items should be taken as signifying a decision, but rather a desire to experiment in a particularly tricky design space.
Ongoing experiments
CopyTypesRelevant previous discussions
This tracking issue is a good place to continue discussion, at least initially; we may ultimately want to break out threads on internals to help hash out preliminary design thoughts.
After an experimental period, the expectation is that whatever designs are deemed sufficiently plausible are turned into fresh RFCs, and then go through the standard process.