Change append operator to concatenation operator (#14344)

# Description

The "append" operator currently serves as both the append operator and
the concatenation operator. This dual role creates ambiguity when
operating on nested lists.

```nu
[1 2] ++ 3     # appends a value to a list [1 2 3]
[1 2] ++ [3 4] # concatenates two lists    [1 2 3 4]

[[1 2] [3 4]] ++ [5 6]
# does this give [[1 2] [3 4] [5 6]]
# or             [[1 2] [3 4] 5 6]  
```

Another problem is that `++=` can change the type of a variable:
```nu
mut str = 'hello '
$str ++= ['world']
($str | describe) == list<string>
```

Note that appending is only relevant for lists, but concatenation is
relevant for lists, strings, and binary values. Additionally, appending
can be expressed in terms of concatenation (see example below). So, this
PR changes the `++` operator to only perform concatenation.

# User-Facing Changes

Using the `++` operator with a list and a non-list value will now be a
compile time or runtime error.
```nu
mut list = []
$list ++= 1 # error
```
Instead, concatenate a list with one element:
```nu
$list ++= [1]
```
Or use `append`:
```nu
$list = $list | append 1
```

# After Submitting

Update book and docs.

---------

Co-authored-by: Douglas <32344964+NotTheDr01ds@users.noreply.github.com>
This commit is contained in:
Ian Manske
2024-11-24 10:59:54 -08:00
committed by GitHub
parent dd3a3a2717
commit 4d3283e235
20 changed files with 131 additions and 201 deletions

View File

@ -31,7 +31,7 @@ impl Command for HelpOperators {
let mut operators = [
Operator::Assignment(Assignment::Assign),
Operator::Assignment(Assignment::PlusAssign),
Operator::Assignment(Assignment::AppendAssign),
Operator::Assignment(Assignment::ConcatAssign),
Operator::Assignment(Assignment::MinusAssign),
Operator::Assignment(Assignment::MultiplyAssign),
Operator::Assignment(Assignment::DivideAssign),
@ -48,7 +48,7 @@ impl Command for HelpOperators {
Operator::Comparison(Comparison::StartsWith),
Operator::Comparison(Comparison::EndsWith),
Operator::Math(Math::Plus),
Operator::Math(Math::Append),
Operator::Math(Math::Concat),
Operator::Math(Math::Minus),
Operator::Math(Math::Multiply),
Operator::Math(Math::Divide),
@ -144,8 +144,8 @@ fn description(operator: &Operator) -> &'static str {
Operator::Comparison(Comparison::StartsWith) => "Checks if a string starts with another.",
Operator::Comparison(Comparison::EndsWith) => "Checks if a string ends with another.",
Operator::Math(Math::Plus) => "Adds two values.",
Operator::Math(Math::Append) => {
"Appends two lists, a list and a value, two strings, or two binary values."
Operator::Math(Math::Concat) => {
"Concatenates two lists, two strings, or two binary values."
}
Operator::Math(Math::Minus) => "Subtracts two values.",
Operator::Math(Math::Multiply) => "Multiplies two values.",
@ -163,8 +163,8 @@ fn description(operator: &Operator) -> &'static str {
Operator::Bits(Bits::ShiftRight) => "Bitwise shifts a value right by another.",
Operator::Assignment(Assignment::Assign) => "Assigns a value to a variable.",
Operator::Assignment(Assignment::PlusAssign) => "Adds a value to a variable.",
Operator::Assignment(Assignment::AppendAssign) => {
"Appends a list, a value, a string, or a binary value to a variable."
Operator::Assignment(Assignment::ConcatAssign) => {
"Concatenates two lists, two strings, or two binary values."
}
Operator::Assignment(Assignment::MinusAssign) => "Subtracts a value from a variable.",
Operator::Assignment(Assignment::MultiplyAssign) => "Multiplies a variable by a value.",