Extending spread operators to work with numbers

# John Gardner (9 years ago)

Probably a stupid idea, and I can see it already being brought up several times... but why not extend spread operators to work with numeric ranges?

	let a = [ 0 ... 3 ];
	// Expands to: [ 0, 1, 2, 3 ]

This wouldn't be a groundbreaking feature, but it would allow better readability when plotting a range of values:

	let esVersions = [ 1 ... 5, 2015 ];

It might also be used to extract a range of values:

	array[ 3 ... 6 ] = "ABCDEFGH";
	// [ "D", "E", "F", "G" ]

Which I find far more readable than this:

	array[ , , , , 3, 4, 5, 6 ] = "ABCDEFGH";

Since it would require two numbers to be explicitly supplied on each side, there's no risk of it being misinterpreted as an attempt to spread an array. Decimal components would be dropped:

	let a = [ 1 ... 3.9 ];
	// [ 1, 2, 3 ]

This would complement Alican's suggested syntax for slicing an array of values, which modifies the original array.

Thoughts? Just throwing crap out there.

# kdex (9 years ago)

You're saying that it has already been brought up; would you mind linking to the relevant threads, then?

Other than that, I really like this syntax. Should this also work when the range is specified dynamically, and not in terms of number literals? And what about parsing it next to a "regular" spread operator?

let a = () => [3];

let b = () => [7];

let string = "Hello, world!";
let range = string[...a() ......b()];
// "lo, w"
# John Gardner (9 years ago)

Heh, I said it's probably been brought up.

*> Should this also work when the range is specified dynamically, and not

in terms of number literals?*

Certainly. Each value around the spread operator would be coerced to an integer, following the standard pattern of numeric evaluation. Then the decimal component, if any, would be ignored, and the resulting value used.

> And what about parsing it next to a "regular" spread operator?

"Regular" spread operators should take precedence. The order of evaluation would be like this:

let range = [ ...[1, 3] ... ...[6, 7] ]; // -> [1, 3 ... 6, 7]; // -> [1, 3, 4, 5, 6, 7];

# Mark S. Miller (9 years ago)

The double dot ("..") is the traditional infix operator for inclusive,inclusive integer ranges, going back to Pascal (the language, not the mathematician). This has all the benefits you seek, including visual clarity, without overloading the meaning of an existing token.

Whether double or triple dot, the problem is that programming patterns in zero-index-origin languages want inclusive,exclusive ranges, which naturally wants an asymmetric syntax to suggest the distinction. The traditional math notation [0, 4) would be unambiguous, since of course we never otherwise allow a closing paren to match an opening square bracket. But, in a programming language context I find it too jarring.

E has ".." for inclusive,inclusive ranges, just like Pascal. E also has "..!" for inclusive,exclusive ranges. The second operator was used much more than the first. I don't think "..!" is great but I don't have anything better to suggest.

Finally, we must ask whether this problem is worth solving with any syntax or at all. We can already express these well enough with APIs. I think this is one of those issues where the benefit of any new syntax here does not pay for its complexity costs. See The Tragedy of the Common Lisp, or, Why Large Languages Explode < esdiscuss.org/topic/the-tragedy-of-the-common-lisp-or-why-large-languages-explode-was-revive-let-blocks

.

See also en.wikipedia.org/wiki/Primum_non_nocere.

# John Gardner (9 years ago)

This has all the benefits you seek, including visual clarity, without overloading the meaning of an existing token.

Actually, I beg to differ. Recall that this is valid syntax:

1.. toString(16);

Furthermore, maintaining a 3-dot notation stays consistent with the rest and spread operators, both of which already overload each other. For sake of clarity for this discussion, I'll call this one the "range operator".

I think this is one of those issues where the benefit of any new syntax here does not pay for its complexity costs.

I don't foresee this raising any complexity issues. The syntax is intended chiefly as a way to specify multiple integers where indexed access is relevant. There wouldn't be any need to specify exclusive or inclusive expansion, because it'd always work inclusively. Which is what I believe every author would expect when they write 1 ... 5.

It would also enable one to write this:

func( 0 ... 5 )

Instead of this:

func( ...[0, 1, 2, 3, 4, 5] );

I can't speak on anybody else's behalf, but I know which of the two I'd prefer writing.

Again, I'll state I don't expect this to be a groundbreaking feature. But it's simple, clean and (from what I understand) would be unintrusive to the language.

# Michał Wadas (9 years ago)

I want to ask why new syntax would be better than Python-like range function?

Cons of range:

  • normal function rather than new syntax
  • can be used as memory efficient generator
  • custom step can be defined
  • easy to polyfill
  • can't make mistake (consider [a...b] vs. [a,...b] - is it easy to see difference?)

Disadvantages:

  • longer than custom syntax
# John Gardner (9 years ago)

The range operator wouldn't attempt to fill every duty that a Python-like range function would. I'd envision it being kept intentionally simple (no custom steps, for example). It looks like what it does, and there's no reason the two couldn't co-exist.

*can't make mistake (consider [a...b] vs. [a,...b] - is it easy to see

difference?)*

That's a non-argument pertaining to an author's formatting choice.

# kdex (9 years ago)

Just a quick idea: The range operator could also be used for non-numeric ranges:

let latin = ["a" ... "z"];
// ["a", "b", "c", ..., "x", "y", "z"]
let latinBackwards = ["z" ... "a"];
// ["z", "y", "x", ..., "c", "b", "a"]
let emoji = ["\u{1F601}" ... "\u{1F64F}"]
// ["\u{1F601}", "\u{1F602}", …, "\u{1F64E}", "\u{1F64F}"]
# Isiah Meadows (9 years ago)

If this says anything, both CoffeeScript and LiveScript implement this operator. I'm neutral on the proposal, though.