# Spread operator ideas
## Definition
This is taken from [javascript documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax).
Spread syntax looks exactly like rest syntax. In a way, spread syntax is the opposite of rest syntax. Spread syntax "expands" an array into its elements, while rest syntax collects multiple elements and "condenses" them into a single element.
## Possible operators:
- `...expr` - This is probably best because it mirrors the rest operator
- e.g. `...$var` - Referencing a variable and spreading it (used in examples below)
- `*expr`
- `expr*`
- `..` - Because `match` uses `..`
## Places allowed:
- Making lists
- Making records
- Making tables
- ~~Pattern matching~~ - When matching on lists and records, it uses `..$rest` rather than `...$rest` to mirror parameters (I guess that's because that's what Rust does?)
## Possible problems
- If someone has a command called `...` or`*`, then something like `{ ... (expr) }` could be intended as a closure that calls `...` on `(expr)`.
- One possible fix is to require not having spaces between the spread operator and the expression.
- Another possible "fix" is to tell users to use `^...`
- Not really a problem, but `match` uses `..` to match the remaining elements of lists and records. The fact that it's different might confuse people.
## Syntax
- `...` only recognized before `$variables`, `[lists]`, and `(subexpressions)` (no whitespace in between)
- No error signalled (yet) for `...` outside lists
## Examples
These examples are just thought starters. Nothing is "in stone" yet.
#### Example 1
Spread the `$rest` of parameters to command line arguments for external applications.
```
def test [...rest] {
^external_cmd ...$rest
}
```
#### Example 2
Spread the list into a command (nushell already does this)
```
let numbers = [1 2 3]
$numbers | math sum
```
#### Example 3
Spread the list into variables (not sure if this destructuring is included)
```
let numbers = [1 2 3 4]
let (a b c d) = ...$numbers
$a = 1
$b = 2
$c = 3
$d = 4
```
#### Example 4
Spread the string into a record?
```
let s = ..."test"
{"0": "t", "1": "e", "2": "s", "3": "t"}
```
> Note: spreading strings not supported, at least temporarily, as ambiguity about how to split
#### Example 5
Spread list into another list?
```
let parts = ["shoulders", "knees"];
let lyrics = ["head", ...$parts, "and", "toes"];
// ["head", "shoulders", "knees", "and", "toes"]
```
#### Example 6
Spread list of lists into a table?
```
let list2d = [[1 2] [3 4]];
let table = [[x y]; ...$list2d];
// [[x y]; [1 2] [3 4]]
```
Error at runtime if too many columns
```
let list2d = [[1 2] [3 4 5 6]];
let table = [[x y]; ...$list2d];
// Error: too many columns, expected 2 but got 4
```
Error at runtime if too few columns (alternative: put in nulls)
```
let list2d = [[1 2] [3 4 5 6]];
let table = [[w x y z]; ...$list2d];
// Error: too few columns, expected 4 but got 2
```
#### Example 7
Bare strings
```
[...echo foo]
// Either [{"0": "e", "1": "c", "2": "h", "3": "o"} "foo"]
// or [["e", "c", "h", "o"] "foo"]
// (see example 4)
```
> Note: spreading strings not supported, at least temporarily, as ambiguity about how to split
#### Example 8
Passing arguments to fill in rest parameters (like Example 1)
```
def foo [bar: string, ...baz: string] {}
foo "quux" "xyzzy" ...$args "last"
// $baz would contain "xyzzy", the items in $args, and "last"
```