Can we have this API?
impl<T> Vec<T> {
pub fn push(&mut self, value: T) -> &mut Self;
}
So we can allow the following pattern:
pub fn foo() -> Vec<char> {
Vec::new().push('f').push('o').push('o')
}
Can we have this API?
impl<T> Vec<T> {
pub fn push(&mut self, value: T) -> &mut Self;
}
So we can allow the following pattern:
pub fn foo() -> Vec<char> {
Vec::new().push('f').push('o').push('o')
}
We could consider supporting method cascading for Rust. With the support, returning &mut Self is unnecessary.
Smalltalk and Dart have native (syntax-level) support for method cascading.
From that wiki link:
Method cascading is much less common than method chaining – it is found only in a handful of object-oriented languages, while chaining is very common.
Also from Method cascading - Wikipedia
Given a method call
a.b()
, after executing the call, method cascading evaluates this expression to the left object a (with its new value, if mutated), while method chaining evaluates this expression to the right object.Chaining
The following chain (in C++):
a.b().c();
is equivalent to the simple form:
b = a.b(); b.c();
Cascading
The following cascade (in Dart):
a..b() ..c();
is equivalent to the simple form:
a.b(); a.c();
For what it is worth we already have support for chaining. So I feel that adding cascading would be surprising.
I also feel that chaining is the least surprising of the two since the rule is simpler and more consistent.
In the short term, method cascades can be fairly easily replicated via macros: https://crates.io/crates/cascade
Note that one can have non-native method cascading in Rust today via the cascade
crate.
EDIT: Well done @17cupsofcoffee, you beat me to it by ~1 min
I think we can't as this is breaking change. This would stop compiling:
fn push_something(v: &mut Vec<usize>) {
v.push(42) // no semicolon here
}
This is unidiomatic code, but still code that should be accepted today. It would complain about type mismatch after that.
I tried to build rustc locally with the proposed API but it caused multiple type interference breakages.
Definitely not worth it.
You can always implement this yourself by defining an extension trait. As a bonus, you can add an impl for both Vec<T>
and &mut Vec<T>
. This would fix the error in your example (function foo
returns a Vec
and the expression inside yields a &mut Vec
).
How it could look: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=dc51b3bb17827c08a5adaeab5593edeb
Personally I'd expect the return value to be, if anything, a reference to the element:
pub fn push(&mut self, value: T) -> &mut T;
so you could push a base value and then manipulate it in place.
This is also unnecessary because Vec<T>
is Extend<T>
, so you can just provide an iterator if you want to append multiple elements.
Given that @tesuji tried with the other form and it broke even rustc how about the following signature:
pub fn push_and_modify(&mut self, value: T) -> &mut T;
Note that that code wouldn't compile with the proposal; it would still need to be
let mut v = Vec::new();
v.push('f').push('o').push('o');
v
But really, the right way to support repeated-push is when we have IntoIterator
for arrays and thus you can just do .extend(['f', 'o', 'o'])
. That's less typing and more efficient, since it can reserve
better.
(And of course the actual snippit is better with vec!
, but I assume that's tangential and you're actually doing this for a vector you already have, not a new one)
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.