Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

question about import operator <<< #1080

Open
determin1st opened this issue Jan 9, 2019 · 8 comments
Open

question about import operator <<< #1080

determin1st opened this issue Jan 9, 2019 · 8 comments
Labels

Comments

@determin1st
Copy link

should this code work?

a =
 p1: 1
 p2: 2
<<<
 p3: a.p1 + a.p2
 p4: 4

a

because, this one works:

a =
 p1: 1
 p2: 2
<<<
 p3: a.p1 + a.p2

a

also, when used import all, it works:

a =
 p1: 1
 p2: 2
<<<<
 p3: a.p1 + a.p2
 p4: 4

a
@rhendric rhendric added the bug label Jan 9, 2019
@rhendric
Copy link
Collaborator

rhendric commented Jan 9, 2019

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.

@vendethiel
Copy link
Contributor

Clearly it should be parsed this way..:)

a =
 p1: 1
 p2: (2
<<<
 p3: a.p1 + a.p2
 p4: 4)

@determin1st
Copy link
Author

@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

@rhendric
Copy link
Collaborator

rhendric commented Jan 9, 2019

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?

@rhendric
Copy link
Collaborator

rhendric commented Jan 9, 2019

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

LiveScript/test/operator.ls

Lines 317 to 319 in bc1c188

f = ->
import it
<<< new: -> new this it

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?

@determin1st
Copy link
Author

determin1st commented Jan 9, 2019

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.

@rhendric
Copy link
Collaborator

rhendric commented Jan 9, 2019

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

@determin1st
Copy link
Author

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants