4 ms·
> in just about every sane language (not to mention plain-old mathematics), extraneous parentheses don't behave like this. Let's test that out. Python 3 doesn
by abbeyj 5y ago
> in just about every sane language (not to mention plain-old mathematics), extraneous parentheses don't behave like this.
Let's test that out.
Python 3 doesn't like extra parentheses:
a = ['hello', 'world']
print(*a) # OK
print((*a)) # ERROR
Ruby doesn't like extra parentheses:
a = ['hello', 'world']
puts(*a) # OK
puts((*a)) # ERROR
C++ doesn't have a splat for C-style varargs functions but it does have one for template parameter packs and it doesn't like extra parentheses:
template <typename ...Args>
void g(Args... x) {
f(x...); // OK
f((x...)); // ERROR
}
Go doesn't like extra parentheses:
package main
import "fmt"
func main() {
a := []interface{}{"hello", "world"}
fmt.Println(a...) // OK
fmt.Println((a...)) // ERROR
}
Lua doesn't like extra parentheses:
a = {"hello", "world"};
print(table.unpack(a)); -- OK
print((table.unpack(a))); -- Only prints "hello"
Perl does like extra parentheses (but then again it doesn't really have a special "splat" syntax and just flattens all lists everywhere):
my @a = ("hello", "world");
print(@a); # OK
print((@a)); # OK
You seem to want `...` to behave as an operator, but it really can't since it doesn't produce a value. If you think it *should* produce a value you then have to decide what the type of that value should be and there doesn't seem to be a good answer for that. I mean, should this be allowed?
let a = ['hello', 'world'];
let b = (...a); // What should the type of `b` be?
// Somehow equivalent to console.log('hello', 'world')?
console.log(b);
I suppose you could introduce some MagicFlattening type into the language and make `b` be of that type. Then every time any function is called the interpreter would have to check and see if the argument is a MagicFlattening object and, if so, change the call from having 1 argument to having N arguments. This would make things slower and make creating a JIT more difficult. It would have unfortunate ripple effects across the entire language. You've now got these magic objects floating around that can unexpectedly change the meaning of any function call in your program. This is probably why most languages have chosen not to go this route.
Instead `...` is a different way of calling a function. You can call a function in the normal way with `(` and `)` and you call it in this alternate way with `(`, `...`, and `)`. Any given call site only uses one or the other of these ways and which one it uses is known at compile time so there's no need for runtime checks and no magic objects.
The `...` is part of the function call so wrapping it in extra parentheses doesn't really make sense. You wouldn't change `console.log(a, b)` to `console.log((a, b))` and expect it to work the same, would you?
- dvt 5y agoFirst off, you're plain wrong about Python, so I doubt the veracity of the other examples (particularly in languages I'm not an expert in, like Ruby). But either way, you (along with the other folks commenting) are missing the point entirely, so I'm not sure you're actually familiar with the language spec nit I'm criticizing. Why `console.log` fails on `((...x))` is not because the function can't take arrays as arguments (in fact, it can: `console.log(["hello","world"])` works fine), but rather because it's running into another spec: inline arrow function notation, i.e., `(...x) => true`. So the spec (because it's so confusing) thinks I'm trying to define a function. That is the problem here, not the splat. > You wouldn't change console.log(a, b) to console.log((a, b)) and expect it to work the same, would you? Honest question, are you aware of the comma operator and how it works?
- minitech 5y ago> First off, you're plain wrong about Python They’re not. The syntax was changed sometime between Python 3.8 and 3.10 to stop working (which should be a big hint about the consensus here). As I suspected, that it worked was accidental from the very beginning: https://bugs.python.org/issue40631#msg384094 https://bugs.python.org/issue40631#msg384094 > Why `console.log` fails on `((...x))` is not because the function can't take arrays as arguments (in fact, it can: `console.log(["hello","world"])` works fine), but rather because it's running into another spec: inline arrow function notation, i.e., `(...x) => true`. So the spec (because it's so confusing) thinks I'm trying to define a function. What does taking arrays as arguments have to do with anything? Are you suggesting `console.log((...x))` should be equivalent to `console.log([...x])`? `(...x)` doesn’t fail to work because some kind of syntax conflict with arrow functions[1]. It fails to work because it’s not defined in the language, and it’s not defined in the language because it doesn’t make sense. You’re the only person who seems to think it does. And if you want to use parentheses for readability, you should write `...(expr)`, `*(expr)`, etcetera. [1] f((a = {})) and f((a = {}) => {}), for example, are both valid expressions where the inner parentheses mean completely different things, analogous to the ellipsis.
- abbeyj 5y ago> First off, you're plain wrong about Python As pointed out by minitech, this syntax was allowed in some versions of Python 3 but that was a bug which has since been fixed. I didn't run into this bug in the version of Python 3 that I used for testing so I had no idea of the bug's existence. > I doubt the veracity of the other examples Python 3.10: https://godbolt.org/z/Po7K7cvY8 https://godbolt.org/z/Po7K7cvY8 Ruby 3.0.2: https://godbolt.org/z/Ke5oWzaW3 https://godbolt.org/z/Ke5oWzaW3 C++ (clang 13.0.0): https://godbolt.org/z/zd5MfM4Mo https://godbolt.org/z/zd5MfM4Mo Go (amd64 gc 1.17): https://godbolt.org/z/KrEsKaTjq https://godbolt.org/z/KrEsKaTjq Lua (luac 5.3.3): https://ideone.com/irl89j https://ideone.com/irl89j Perl (perl 2018.12): https://ideone.com/YZcCAC https://ideone.com/YZcCAC > Honest question, are you aware of the comma operator and how it works? I am. The existence of the comma operator is the reason that `console.log((a, b))` parses (and means something different than `console.log(a, b)`). If we consider a hypothetical version of JavaScript which does not have the comma operator then `console.log((a, b))` wouldn't parse at all! The comma there can't be the comma operator because we've removed that. And it can't be part of the function call because then the first argument to the function call would have to be `(a` which is obviously not a valid expression. And it can't be part of an array literal or an object literal because it isn't inside of `[]` or `{}`. That leaves us with no valid ways for this to parse. You can usually add extra parentheses around any expression without changing the meaning. But "all the arguments to a function" is *not* an expression (except in the case where there happens to be exactly one argument). This is why it doesn't make sense to change `console.log(a, b)` into `console.log((a, b))`, why it doesn't make sense to change `console.log()` into `console.log(())`, and why it doesn't make sense to change `console.log(...a)` into `console.log((...a))`.