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

Variable assignment with arithmetic (Operator precedence) #1928

Open
MondayHopscotch opened this issue Jun 17, 2019 · 4 comments
Open

Variable assignment with arithmetic (Operator precedence) #1928

MondayHopscotch opened this issue Jun 17, 2019 · 4 comments
Labels

Comments

@MondayHopscotch
Copy link

Describe the bug
Arithmetic operations combined with variable assignment leads to unintuitive parsing.

To Reproduce
https://jqplay.org/s/EYE60uy1jx

Input

["a", "b", "c"]

JQ

length + 1 as $array_length | $array_length | debug

Output

["DEBUG:",1]
4

The value of $array_length is 1, instead of the expected 4

Expected behavior
The grouping during parsing seems unintuitive and/or incorrect here.

What the current implementation is doing:

length + (1 as $array_length | $array_length | debug)

What I would expect:

(length + 1) as $array_length | $array_length | debug

Environment (please complete the following information):

  • JQ Play, listed as running 1.6

Additional context
This is the simplest example I could create, but in more complicated examples, this creates some unintuitive results:

I ended up here while trying to figure out why something like this example wasn't working:
https://jqplay.org/s/EHrQ49_MDl

Input:

{
    "foo": 5
}

JQ:

def testFunc($input): 
    $input + 5 as $new | 
    {"original": $input, "new": $new}
;

testFunc(.foo)

Result:

jq: error (at <stdin>:2): number (5) and object ({"original"...) cannot be added
exit status 5

I understand I can get around this issue by explicitly adding some parentheses to force the grouping in the way I am wanting, or by removing the $new variable declaration and just in-lining it in the object constructor. These are just examples to show the behavior I was dealing with.

@nicowilliams
Copy link
Contributor

Yes, jq has some precedence issues. I don't think they can be fixed now. Perhaps we could add higher- and lower-precendence versions of various operators, not unlike Haskell, but that's about all we can do.

I.e., something like length $+ 1 as $foo | ... having addition bind more tightly than the as $foo.

Not sure that it's worth doing.

Comments?

@MondayHopscotch
Copy link
Author

I think it's something that would be useful eventually to get a more intuitive behavior. I'm not super familiar with the underlying code, so I don't know how much work it would entail. Since I am able to work around the current limitations by adding some ()'s around pieces to guarantee the grouping, it's nothing urgent.

@MondayHopscotch MondayHopscotch changed the title Variable assignment with arithmetic Variable assignment with arithmetic (Operator precedence) Jun 18, 2019
@wtlangford
Copy link
Contributor

I don't like the idea of having otherwise-identical operators with different precedence semantics. I think that's likely to be more confusing long-term. (See the difference between && and and in Ruby for an example)

In a world with a formal compile step, I might consider adding a warning (similar to what you get when you do a && b || c in c)

That said, I wouldn't want to add warning output like that here.

@MondayHopscotch
Copy link
Author

MondayHopscotch commented Jun 18, 2019

I was imagining it differently than how you have described it @wtlangford.

I see as as somewhat of its own thing. More of a 'terminating' token rather than an operator that expects a left and a right operand. Operators like + have arbitrary left and right operands, while as has an arbitrary left operand, and a syntactically locked right 'operand' (which is a strict $<varName>.

So something more complicated like

... | length + 1 / 6 % 2 as $foo | ... would still parse equivalent to ... | (length + 1 / 6 % 2) as $foo | ... because the as would, as worded above, 'terminate' the parsing of the right side operands to all the mathematic operators.

Not sure if all of that fits in with the current implementation, but that fleshes out my thoughts a little more.

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

4 participants