Try   HackMD

Spread operator ideas

Definition

This is taken from javascript documentation.

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"