Jump to content

Bug: Ternary expression inside square brackets malfunctioning


Recommended Posts

Hello everyone, I am back with yet another strange behaviour in AutoIt :)

While working on my project I stumbled upon this weird error in this script:

Local $aArray = ["Foo", "Bar", "Baz"]

; Works
ConsoleWrite($aArray[($aArray[0] = "Foo" ? 1 : 2)] & @CRLF)

; Doesn't work
ConsoleWrite($aArray[$aArray[0] = "Foo" ? 1 : 2] & @CRLF)
Quote

Bar
"E:\Projects\AutoIt\AIO Test Script.au3" (7) : ==> Unbalanced brackets in expression.:
ConsoleWrite($aArray[$aArray[0] = "Foo" ? 1 : 2] & @CRLF)
ConsoleWrite($aArray[^ ERROR

I am using the ternary operator to dynamically select a different element based on the value inside another element, instead of going the more traditional and simple (as in concept) approach of using If...Else

The problem is that the interperter thinks the square brackets are unbalanced :sweating:. It works if I wrap the entire expression inside curvy brackets (parentheses)

 

I would like to see what the developers have to say about this :D. IMO this is definitley a bug in the interpreter's parser, I would be happy to open a ticket if we determine that this needs to be fixed.

Edited by TheDcoder
Change title again

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

  • Moderators

TheDcoder,

The Help file does suggest that any ternary expression be enclosed in parentheses (curved brackets). At present you are essentially asking AutoIt to read your mind when you omit the parentheses and expecting it to decide that it should evaluate the ternary expression before using the result as an array index - using the parentheses forces the interpreter to evaluate the ternary first and so everything works as you expect.

To my mind this is not a bug, but an example of poor coding syntax on your part which is not picked up by the interpreter - you cannot expect it to manage every edge case that a human coder can produce.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

Thank you for the reply @Melba23,

I am afraid I would have to disagree with you, while it is true that the help file suggests wrapping a ternary expression in brackets, that doesn't mean it should be required, especially when there are no other operators in the expression.

10 minutes ago, Melba23 said:

At present you are essentially asking AutoIt to read your mind when you omit the parentheses and expecting it to decide that it should evaluate the ternary expression before using the result as an array index

I would hardly classify evaluating the expression and using the result as the value "reading your mind". I absolutely see no room ambiguity or any other interpretations, only a single operator is used in this case.

20 minutes ago, Melba23 said:

To my mind this is not a bug, but an example of poor coding syntax on your part

Please do enlighten me, why is this considered poor coding syntax? I don't think it is better to wrap an expression with a single operator in brackets.

26 minutes ago, Melba23 said:

you cannot expect it to manage every edge case that a human coder can produce.

I agree that it should not be expected to manage every edge case but I would not call it an edge case as it is quite logical to think that an expression should be evaluated before it is used.

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

Local $aArray = ["Foo", "Bar", "Baz"]
Local $aArray2 = [0, 1, 2]

; Works
ConsoleWrite($aArray[$aArray2[1]] & @CRLF)

; Works
ConsoleWrite($aArray[(1?1:2)] & @CRLF)

; Doesn't work
ConsoleWrite($aArray[1?1:2] & @CRLF)

 

Link to comment
Share on other sites

Thanks @LarsJ, the bug only happens if there is a ternary operator it seems. It is interesting because the interpreter still claims that the brackets are unbalanced even if there is only a single pair of them in the statement, maybe the code which handles ternary operator is at fault.

Edited by TheDcoder

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

The ternary operator is probably implemented to be used as an assignment operator this way:

$i = 2
$j = $i = 1 ? 0 : 2

 

If there is no assignment you need the paranthesis:

$aArray = ["Foo", "Bar", "Baz"]
ConsoleWrite($aArray[( $i = 1 ? 0 : 2 )] & @CRLF)

 

Link to comment
Share on other sites

I wild-guess it's a matter of operator priority. Note that AFAIK this (relatively new) ternary op isn't yet listed in help under priority list.

I'd also classify that as minor bug, or at least misfeature.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

  • Moderators

The Dcoder,

Quote

I absolutely see no room ambiguity or any other interpretations

Really? Let us look at the code:

ConsoleWrite($aArray[$aArray[0] = "Foo" ? 1 : 2] & @CRLF)

; The ConsoleWrite is fine, so we get

$aArray[$aArray[0] = "Foo" ? 1 : 2]

; Now AutoIt looks at this code - there are no parentheses to force prior evaluation so it proceeds linearly
; It sees an array element with the content of another array element as index - no problems there
; but then it sees an assignment operator and so thinks you want assign a value to that array element
; But you have not closed the array element definition and so you get an error

; Using parentheses to force the ternary expression to be evaluated first removes this ambiguity

Thus my remark about "poor coding syntax" - do not expect a computer to always think the way you do, make the priority of the elements within an expression absolutely clear. Another good example is using parentheses to clearly define the scope of a Not operator, which often catches out the unwary.

Quote

 I would not call it an edge case as it is quite logical to think that an expression should be evaluated before it is used

I hope the above shows why the interpreter does not do what you think it should - it is actually being quite logical, it is up to you as the coder to clarify your intentions.

And given the possible complexity of many ternary expressions, I think expecting AutoIt to recognise every possible case is asking rather too much. There must be a line drawn between looking for obvious errors and having massively bloated code to cover "every" case - which of course will never be completely watertight as humans are far too ingenious!

So I reiterate my opinion that this is not a bug but an example of poor coding syntax where what appears logical to the coder is not actually seen as such by the interpreter. It is up to the coder to make his intentions clear - and using parentheses to force prior evaluation is a good example. As a matter of fact I always enclose the separate elements of a ternary expression in parentheses as well, so my version would read:

ConsoleWrite($aArray[(($aArray[0] = "Foo") ? (1) : (2))] & @CRLF)

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
Share on other sites

I beg to differ.

In the case at hand the bold red part is an expression which must be evaluated like any other expression (this fails):
ConsoleWrite($aArray[$aArray[0] = "Foo" ? 1 : 2] & @CRLF)

but this bold red expression is correctly interpreted in a different context (this works):
ConsoleWrite($aArray[0] = "Foo" ? 1 : 2)
ConsoleWrite(@CRLF)

If the interpretor would interpret $aArray[0] = "Foo" separately, it wouldn't see an assignment but an equality test (which the first part of a ternary actually is). And indeed this is what happens in (works):
ConsoleWrite($aArray[$aArray[0] = "Foo"] & @CRLF)

The result of such a test is (here) the boolean True, so the inirial bold red expression would then become
ConsoleWrite($aArray[True ? 1 : 2] & @CRLF)
But this bold now green expression isn't evaluated correctly either in this context.

Yet the same expression is correctly evaluated in another context:
ConsoleWrite(True ? 1 : 2)
ConsoleWrite(@CRLF)

Hopefully AutoIt is meant to have an almost context-free grammar (we have no == operator) but this example demonstrates that <expr> isn't parsed the same in
Function(<expr>)
and
Function($a[<expr>])

This is why I stand behind my statement that it's a bug. I called it minor because it's dead easy to work around, but bugs in expression parsers are fundamental to any language. A parser MUST be consistent and psychorigid.

The advice in help to enclose ternary expressions in () arose mostly because newbies tend to write things like
ConsoleWrite($x = "Three" ? 3 : 0 & @CRLF)
and be surprised by the outcome.

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

Hello Melba,

I agree that using parentheses is a good practice and it certainly helps the interperter know what is in your mind. And you are indeed correct about it "linearly" evaluating the expression and mistaking the = operator for being used for assignment :D this code proves it:

Local $aArray = ["Foo", "Bar", "Baz"]

; Works (no equal operator)
ConsoleWrite($aArray[$aArray[0] <> "Foo" ? 1 : 2] & @CRLF)

; Doesn't work
ConsoleWrite($aArray[$aArray[0] = "Foo" ? 1 : 2] & @CRLF)
ConsoleWrite($aArray[$aArray[0] == "Foo" ? 1 : 2] & @CRLF)

As I was writing my reply, @jchd came up with exactly what I was trying to demonstrate. Kudos and thanks :thumbsup:

This would only require correcting the context in which the expressions are evaluated inside the square brackets of an array, so that = doesn't get mistaken.

8 minutes ago, jchd said:

(we have no == operator)

Small correction: We do have that, it is the case-sensitive comparision operator :), but as I have demonstrated in my code above, it still doesn't work.

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

I meant that = is double-headed in AutoIt and was refering to C/C++ or other ==

5 minutes ago, TheDcoder said:

This would only require correcting the context in which the expressions are evaluated inside the square brackets of an array, so that = doesn't get mistaken.

The parser isn't confused by = as this show (fails too)
ConsoleWrite($aArray[1 ? 1 : 2])

This wonderful site allows debugging and testing regular expressions (many flavors available). An absolute must have in your bookmarks.
Another excellent RegExp tutorial. Don't forget downloading your copy of up-to-date pcretest.exe and pcregrep.exe here
RegExp tutorial: enough to get started
PCRE v8.33 regexp documentation latest available release and currently implemented in AutoIt beta.

SQLitespeed is another feature-rich premier SQLite manager (includes import/export). Well worth a try.
SQLite Expert (freeware Personal Edition or payware Pro version) is a very useful SQLite database manager.
An excellent eBook covering almost every aspect of SQLite3: a must-read for anyone doing serious work.
SQL tutorial (covers "generic" SQL, but most of it applies to SQLite as well)
A work-in-progress SQLite3 tutorial. Don't miss other LxyzTHW pages!
SQLite official website with full documentation (may be newer than the SQLite library that comes standard with AutoIt)

Link to comment
Share on other sites

I didn't notice that at all! :o

Very surprising and interesting... I am not sure what is going wrong in this case, and I reckon we cannot test furthur as we cannot remove the remaining symbols in the expression.

 

I have to change the title yet again... maybe I should make it more generic.

EasyCodeIt - A cross-platform AutoIt implementation - Fund the development! (GitHub will double your donations for a limited time)

DcodingTheWeb Forum - Follow for updates and Join for discussion

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...