Vector Concatenation

Why doesn't Vec implement Add and AddAssign? I know some people don’t like the fact that + is overloaded for concatenation, but the standard library already provides String + &str, so why not implement it for Vec and other collections?

impl<T> Add<T> for Vec<T> {
    type Output = Self;

    fn add(self, other: T) -> Self {
        self.push(other);
        self
    }
}

impl<T> AddAssign<T> for Vec<T> {
    fn add_assign(&mut self, other: T) {
        self.push(other);
    }
}
1 Like

Using + for concatenation seems reasonable, but also + could be used for element-by-element addition:

let a = vec![1,4,5];
assert_eq!(a + 1, vec![2, 5, 6]);

My guess is that there are enough different interpretations about what + should mean for Vecs that it makes sense to not provide one in the standard library, as to remove possible avenues of confusion

11 Likes

I really really doubt that someone would expect that behavior from +, but I see your point. Maybe Rust should have a different concat operator, like d's ~ or Scala's ++ and :::.

1 Like

Almost all vector-matrix math libraries/languages work like that.

2 Likes

Consider also that concat for fixed-size arrays doesn't work, but + still makes plenty of sense when done element-wise.

2 Likes

Note that there are many people who complain about + on strings existing at all, so it's not great precedent to use.

Well, += might not, but + still could, as in [1, 2] + [3, 4, 5] => [1, 2, 3, 4, 5].

6 Likes

Okay, so how about removing (or deprecating) + for strings and adding a new trait (Concat) and a new concat (~) operator? This would make the standard library more consistent and we would have better ergonomics for concatenation.

3 Likes

More consistent with what? You can't concat HashMaps in the same way you can Vecs, and you don't want to concat String in the same way as &str. Concatenating arrays changes the type. What API are you proposing, and where would it actually apply?

3 Likes

This has been discussed many times. It would be nice to avoid rehashing the same points and repeating the exact same discussion. Personally I would only engage in such a discussion if someone had already written a detailed RFC (weighing all the options, evaluating what the code churn impact would be, showing justifications for it, etc.) and posted it here as the starting point for the discussion.

8 Likes

Sure, I wasn't aware of that discussion. I'll try to write up a Pre-RFC for concatenation and post that when I have time :+1:

1 Like

And more importantly, why do we need another operator? It could just be a function. There's no well-established notation for concatenation (unlike basic arithmetic operations), so it doesn't really carry its weight.

3 Likes

You mean arithmetical operations. Concatenation is very much a mathematical operation: it's the multiplication of the free monoid over a set/type. (And no, I am not suggesting the use of * for concatenation in Rust.)

5 Likes

Also Ruby:

>> [1,2,3] + [4,5,6]
=> [1, 2, 3, 4, 5, 6]

...and Python

>>> [1,2,3]+[4,5,6]
[1, 2, 3, 4, 5, 6]
2 Likes

Ruby and Python are not primarily scientific computing languages. In R, however…:

x = c(1, 2, 3);
y = c(4, 5, 6);
x + y

[1] 5 7 9

There's also NumPy and its ndarray for Python, Matlab, etc., which all perform element-wise addition, and concatenation is a bit more elaborate syntactically.

5 Likes

If we are picking nits: everything is mathematics, isn't it? (I've amended my post anyway.)

1 Like

Why does String + &str exist then? It's a just a function (and please don't point "other mainstream languages": this is exactly the kind widespread insonsistencies that would deserve to get done right at least once). Anyway I agree with @mjbshaw: this topic has already been discussed many time and certainly a RFC is the only productive way to make it move forward.

I would like to point this post to @ibraheemdev where I tried to show that more generally the Rust operator story as a whole would need clarification if we want to have a constructive discussion.

I don't know. I didn't put it there, and I didn't argue it was necessary or useful.

On the contrary, I certainly wouldn't miss String + &str if it didn't exist or if it was removed. It's inconsistent with basically all other uses of + in std. I don't remember a single time that I needed or used it, since there is format!() and push_str() and [String]::join() and a myriad of other tools which are clearer and more useful than +. If I were in charge, I would simply remove it from std.

6 Likes

IMHO by mistake. It just confuses users when &str + &str doesn't work, or that String + &str is actually += because it consumes the string. Higher-level/dynamic languages can make "clever" operators work, but it's a poor fit for Rust where ownership and lack of implicit copies make it more than just + operation.

17 Likes

Could this be deprecated in the 2021 edition?

Trait implementations cannot currently be deprecated at all, even in user code.