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

Allow implicit coercions for cross-borrows. #226

Closed
wants to merge 1 commit into from

Conversation

nrc
Copy link
Member

@nrc nrc commented Sep 3, 2014

Wherever a type implements Deref<T>, allow an implicit coercion to &T. Removes the need for most occurrences of &*.

Wherever a type implements `Deref<T>`, allow an implicit coercion to `&T`. Removes the need for most occurrences of `&*`.
@lilyball
Copy link
Contributor

lilyball commented Sep 4, 2014

I've been a big fan of this idea in the past. I'm not as much of a fan today, primarily because it makes it slightly harder to figure out whether a given expression is a move/copy or a cross-borrow, but I think I still fall in the 👍 camp.

I'm also in favor of implementing Deref on Vec/String in light of this RFC, to get rid of all those .as_string() calls. I'm in favor of doing that even without this RFC, because saying &*strvar is still better than strvar.as_slice().

For what it's worth, we already have some inconsistency in moves vs borrows with macros. I can say

let s: String = foo();
println!("{}", s); // note: bare `s`
consume_string(s);

But I can't say

let s: String = foo();
io::println(s); // bare `s` again, this time it's moved
consume_string(s);

This RFC coupled with a Deref impl on String would let the latter snippet work just as the former snippet does.

@lilyball
Copy link
Contributor

lilyball commented Sep 4, 2014

This also seems related to rust-lang/rust#13910, which needs an RFC (extending support for box in patterns to work with arbitrary smart pointers).

@lilyball
Copy link
Contributor

lilyball commented Sep 4, 2014

FWIW, UFCS provides an argument in favor of more drastic auto-borrowing, because if any type T could be borrowed to &T when given as a function argument, then any expression foo.bar() (where foo: T) can be rewritten under UFCS as T::bar(foo) without having to know whether the receiver type is by-value or by-reference.

That said, I think it's still appropriate to stick with just cross-borrowing. Full auto-borrowing just seems potentially too problematic.

&e | &e
&*e | e
&**e | *e
&&**e | &*e
Copy link
Member

Choose a reason for hiding this comment

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

I don't understand how this can work?

It seems let x = &&**e; is equivalent to the following today:

let tmp = e.deref().deref();
let x = &tmp;

while the latter seems like it should just be e.deref() (as &*e is now)? Or is there some deep coercions going on here, if so, that doesn't seem like it's backwards compatible, particularly, since &*e could mean two different things.

Copy link
Member Author

Choose a reason for hiding this comment

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

It might be wrong actually. I was imagining *e would happen first, then we would implicitly coerce to &**e and finally the explicit & would give &&**e. If we allow coercions at &e but not at *e, then I think there is no ambiguity. This distinction does seem a bit ad-hoc though (it follows where we have an expected type in the type checker at the moment). I have another RFC which goes in to depth on sites for coercions, for this RFC I'm just kind of assuming that is nailed down elsewhere.

@Ericson2314
Copy link
Contributor

Sounds good, my only reservation is that being able to write &* instead of &&** in the double box case might look misleading. Of course, on the other hand, that follows from the rule, and preventing it would be a crude hack.

Maybe deep cross-borrowing wouldn't be so bad?

@aturon
Copy link
Member

aturon commented Sep 16, 2014

I've posted an alternative design that achieves similar goals but is somewhat more conservative: it only allows coercions on already-borrowed data, and thereby does not introduce new borrows implicitly. The RFC gives detail about the downsided of implicit borrowing.

nrc added a commit to nrc/rfcs that referenced this pull request Sep 19, 2014
Change the address-of operator (`&`) to a borrow operator. This is an
alternative to rust-lang#241 and rust-lang#226 (cross-borrowing coercions). The borrow operator
would perform as many dereferences as possible and then take the address of the
result. The result of `&expr` would always have type `&T` where `T` does not
implement `Deref`.
@aturon aturon mentioned this pull request Sep 22, 2014
@nrc
Copy link
Member Author

nrc commented Sep 30, 2014

Some data and a little discussion: https://gist.github.com/nick29581/809614adb2bbb38232b7

@nrc
Copy link
Member Author

nrc commented Oct 28, 2014

Closed in favour of #241 or something like that (that idea is superior because it better respects the borrowing/ownership principles of Rust and substitutability).

@nrc nrc closed this Oct 28, 2014
wycats pushed a commit to wycats/rust-rfcs that referenced this pull request Mar 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants