Order of Operator Precedence When Using ":" (The Colon)

Order of operator precedence when using : (the colon)

Because the operator : has precedence over + so 1+1:3 is really 1+(1:3) (i. e. 2:4) and not 2:3. Thus, to change the order of execution as defined operator precedence, use parentheses ()

You can see the order of precedence of operators in the help file ?Syntax. Here is the relevant part:

The following unary and binary operators are defined. They are listed in precedence groups, from highest to lowest.

:: ::: access variables in a namespace

$ @ component / slot extraction

[ [[ indexing

^ exponentiation (right to left)

- + unary minus and plus

: sequence operator

%any% special operators (including %% and %/%)

* / multiply, divide

+ - (binary) add, subtract

ANTLR4 precedence of operator

exp    :  left=term (operator=(PLUS | MINUS) right=exp)?

This produces parse tree that is causing it. Simply put, 5 - 2 + 4 will be parsed as:

term  PLUS       exp
2 term MINUS exp
2 term
4

This should help, although you'll have to change the evaluation logic:

exp    :  left=term (operator=(PLUS | MINUS) right=term)*

Same for factor and any other possible binary operations.

Rule useless in parser with two operators in a row

You've specified that the ':' operator is nonassociative. Remove that, and you'll instead get the expected conflicts from A:B:C being parsable as one of A:B:C, (A:B):C and A:(B:C).

But since you want it to be nonassociative, here is one way:

%token tINT

%%

program: { }
| colonexpression ';' { }
;

colonexpression: expression { }
| expression ':' expression ':' expression { }
| expression ':' expression { }
;

expression: tINT { }
;

%%

Applying adverb to colon operator

When modified by an iterator (also known as an adverb in q speak), : behaves just like any other binary operator. In your example

q)(:')[100;2 3 4]
2 3 4

an atom 100 is extended to a conformant list 100 100 100 and then : is applied to elements of the two lists pairwise. The final result is returned. It might look confusing (: tries to modify a constant value, really?) but if you compare this to any other binary operator and notice that they never modify their operands but return a result of expression everything should click into place.

For example, compare

q)+'[100; 2 3 4]
102 103 104

and

q)(:')[100;2 3 4]
2 3 4

In both cases an a temporary vector 100 100 100 is created implicitly and an operator is applied to it and 2 3 4. So the former is semantically equivalent to

(t[0]+2;t[1]+2;t[2]+4)

and the latter to

(t[0]:2;t[1]:2;t[2]:4)

where t is that temporary vector.

This explains why (:')[x;2 3 4] gives an error -- if x doesn't exist kdb can't extend it to a list.

Why does my ternary operator cause a shift-reduce conflict?

If I understand you correctly, you did the following:

%left '+' '-'
%right '?'

%%

arithmetic_expression : expression + expression
| expression - expression
;
ternary : expression ? expression : expression
;

That won't work, because you haven't told bison what the precedence of the ternary production is.

To resolve shift-reduce conflicts, bison compares the precedence of the production which might be reduced with the precedence of the terminal which might be shifted. You've declared the precedence of the terminals '+', '-' and '?', and the precedence of both productions in arithmetic_expression, but not the precedence of the production in ternary.

Quoting from the bison manual, emphasis added:

each rule gets its precedence from the last terminal symbol mentioned in the components.

That's very subtle and you won't be the first person who didn't notice.

Solutions: either declare the precedence of the terminal : or add %prec '?' to the production in ternary.

How is this MATLAB code (involving colon operator) resolved?

Here's the list of MATLAB operator precedence

As you can see, parentheses, (), are solved first, meaning that mod(7:11,5) will be done first. Then point 6), the addition and subtraction are taken care of from left to right, i.e. 11-mod(7:11,5) and then 11-mod(7:11,5)+5. Then point 7), the colon, :, gets evaluated, thus 7:11-mod(7:11,5)+5.

As you noted correctly 7:11 - mod(7:11, 5) + 5 is the same as 7:(11 - mod(7:11, 5) + 5), as seen above using operator precedence.


Now to the second part: why do you obtain 8 values, rather than 5? The problem here is "making an array with an array". Basically:

1:3
ans =
1 2 3
1:(3:5)
ans =
1 2 3

This shows what's going on. If you initialise an array with the colon, but have the end point as an array, MATLAB uses only the first value. As odd as it may sound, it's documented behaviour.

mod(7:11,5) generates an array, [2 3 4 0 1]. This array is then subtracted from 11 and 5 is added [14 13 12 16 15]. Now, as we see in the documentation, only the first element is then considered. 7:[14 13 12 16 15] gets parsed as 7:14 and will result in 8 values, as you've shown.

Doing (7:11) - mod(7:11, 5) + 5 first creates two arrays: 7:11 and mod(7:11,5). It then subtracts the two arrays elementwise and adds 5 to each of the elements. Interesting to note here would be that 7:12 - mod(7:11, 5) + 5 would work, whereas (7:12) - mod(7:11, 5) + 5 would result in an error due to incompatible array sizes.

error: left- and right-associative operators with same precedence may not be mixed

From The Scala Language Specification, section 6.12.3:

The associativity of an operator is determined by the operator’s last
character. Operators ending in a colon ‘:’ are right-associative. All
other operators are left-associative

The compiler doesn't know whether to interpret your code as this:

80.`:`("https".`://`("example.com"))

or this:

"https".`://`(80.`:`("example.com"))

I don't think there's a way to prevent ':' from being treated as a right-associative operator. You could help the compiler out by using parentheses; otherwise, you have to change your operator names.

Does Python have a ternary conditional operator?

Yes, it was added in version 2.5. The expression syntax is:

a if condition else b

First condition is evaluated, then exactly one of either a or b is evaluated and returned based on the Boolean value of condition. If condition evaluates to True, then a is evaluated and returned but b is ignored, or else when b is evaluated and returned but a is ignored.

This allows short-circuiting because when condition is true only a is evaluated and b is not evaluated at all, but when condition is false only b is evaluated and a is not evaluated at all.

For example:

>>> 'true' if True else 'false'
'true'
>>> 'true' if False else 'false'
'false'

Note that conditionals are an expression, not a statement. This means you can't use assignment statements or pass or other statements within a conditional expression:

>>> pass if False else x = 3
File "<stdin>", line 1
pass if False else x = 3
^
SyntaxError: invalid syntax

You can, however, use conditional expressions to assign a variable like so:

x = a if True else b

Think of the conditional expression as switching between two values. It is very useful when you're in a 'one value or another' situation, but it doesn't do much else.

If you need to use statements, you have to use a normal if statement instead of a conditional expression.


Keep in mind that it's frowned upon by some Pythonistas for several reasons:

  • The order of the arguments is different from those of the classic condition ? a : b ternary operator from many other languages (such as C, C++, Go, Perl, Ruby, Java, JavaScript, etc.), which may lead to bugs when people unfamiliar with Python's "surprising" behaviour use it (they may reverse the argument order).
  • Some find it "unwieldy", since it goes contrary to the normal flow of thought (thinking of the condition first and then the effects).
  • Stylistic reasons. (Although the 'inline if' can be really useful, and make your script more concise, it really does complicate your code)

If you're having trouble remembering the order, then remember that when read aloud, you (almost) say what you mean. For example, x = 4 if b > 8 else 9 is read aloud as x will be 4 if b is greater than 8 otherwise 9.

Official documentation:

  • Conditional expressions
  • Is there an equivalent of C’s ”?:” ternary operator?


Related Topics



Leave a reply



Submit