Open determin1st opened 5 years ago
I can imagine two possible reasonable compilations for
a =
p1: 1
p2: 2
<<<
p3: a.p1 + a.p2
p4: 4
The first is
a = { p1: 1, p2: 2, p3: a.p1 + a.p2, p4: 4 };
The second is
(a = { p1: 1, p2: 2 }).p3 = a.p1 + a.p2;
a.p4 = 4;
(This doesn't even address cases like (a = p1: 2) <<< p1: 1, p2: a.p1
; I could argue that after executing this statement, a.p2
ought to equal 2, not 1, despite what LiveScript currently does.)
As the current result of this compilation isn't equivalent to either of these, I'm calling this a bug, but I'm not sure which of my two possibilities should be the result instead. The precedence relation between =
and <<<
seems sensitive to braces and line breaks, and right now I'm not sure how much of that is intentional.
Clearly it should be parsed this way..:)
a =
p1: 1
p2: (2
<<<
p3: a.p1 + a.p2
p4: 4)
@rhendric
Of course the second variant! Isn't it intuitive? The point is to reuse the name of newly created object and add properties that depend on the previous assignment. Your first example equals to this:
a =
p1: 1
p2: 2
p3: a.p1 + a.p2
p4: 4
I used <<<
only for fast code typing, not for fast objects which should be created with constructor/prototype syntax
What do you think about this case:
a = { p1: 1, p2: 2 } <<< p3: a.p1 + a.p2, p4: 4
Is that equivalent to the second variant or the first? How about:
f = -> p1: 1, p2: 2
a = f! <<< p3: a.p1, p4: 4
Or:
f = -> p1: 1, p2: 2
g = -> p3: a.p1, p4: 4
a = f! <<< g!
LiveScript currently interprets all of these as equivalent to the first variant, and I think that's probably correct. Do you agree?
I think the question boils down to explaining why the following two snippets should be different (they currently are):
a = x: 0
b = x: 1
a = b
<<< c: a.x
a.c #=> 0
a = x: 0
b = x: 1
a =
b
<<< c: a.x
a.c #=> 1
This duality exists with many other binary operators (at least, the ones that don't have a different interpretation when they start a line), such as ^
, comparison operators (>
etc.), boolean operators (&&
etc.), composition operators (>>
and <<
), pipes (|>
and <|
), and <<<<
, so at least LiveScript is consistent. The only place I can find the binary-operator-beginning-a-line pattern in LiveScript's tests is
https://github.com/gkz/LiveScript/blob/bc1c188f01298567bc689c979147829c6ac57213/test/operator.ls#L317-L319
but that's a pretty clear indicator that this difference is intentional. This all favors @determin1st's preferred interpretation of his original submission; my only remaining unease is not being able to succinctly explain what the governing principle is here. It's not quite that a binary operator immediately following a dedent will take as its left operand the entire expression leading up to and including the indented block—counterexample:
a <| b do
c
<<< d #=> equivalent to a(b(c) <<< d), not a(b(c)) <<< d
Maybe a binary operator just gets a lower but non-zero precedence when it immediately follows a dedent—less binding than =
, but more binding than <|
? It's not a fixed lower precedence, though—the relative precedence between ^
and >
is preserved in the below:
a do
b
^ c do
d
> e #=> equivalent to (a(b) ^ c(d)) > e
a do
b
> c do
d
^ e #=> equivalent to a(b) > (c(d) ^ e)
Anyone have any good theories for me?
your second example, be it (a = f!) <<< g!
or a = (f! <<< g!)
- doesn't change anything, right? So it's correct. The first:
a = f! <<< p3: a, p4: 4
currently means, that the value of variable a
, is set before the expression starts to run, like:
a = 3
a = f! <<< p3: a, p4: 4
will do a = (f! <<< {p3: a, p4: 4})
, not (a = f!) <<< {p3: a, p4: 4}
. but i'm also okay/agree to the second variant, because i didn't use this syntax ever. it works with objects, not primitive values, so, maybe it's a special case.
your second example, be it (a = f!) <<< g! or a = (f! <<< g!) - doesn't change anything, right?
I'm afraid it does—it's very similar to the other example:
f = -> p1: 1, p2: 2
g = -> p3: a.p1, p4: 4
a = p1: 0
a = (f! <<< g!)
a.p3 #=> 0
a = p1: 0
(a = f!) <<< g!
a.p3 #=> 1
well, your examples are tricky, but i feel, ill be okay with
f = -> p1: 1, p2: 2
g = -> p3: a.p1, p4: 4
a = p1: 0
a = f! <<< g!
a.p3 #=> 1
should this code work?
because, this one works:
also, when used
import all
, it works: