Very tricky LUA bug!

I ran into this bug, took me 1 day to find out. So you better know! I wrote

        local zoneTouched = false
        for i,a in pairs(areas) do
            zoneTouched = zoneTouched or self:checkTouched(i)
        end

I check if an area is touched, and i keep track if at least 1 area is touched in zoneTouched.
Does work with 50% of my areas, not all???
But this works:

        local zoneTouched = false
        for i,a in pairs(areas) do
            test = self:checkTouched(i)
            zoneTouched = zoneTouched or test
        end

Let me tell you what happens (or what i think is happenning) in my first code:

  • i have 5 named fields, accessed in random order with pairs(areas) (lua decides the order).
  • the zone #3 in the access order returns ‘true’. This sets zoneTouched to ‘true’.
  • then for the rest of the fields lua will not evaluate the right part of the ‘or’ because zoneTouched is now true!
    So the fields before #3 were correctly working, the ones after were ignored…
    That drove me crazy for a while… :frowning:
    if i had written in the opposite order:
            zoneTouched =  self:checkTouched(i) or zoneTouched

I think it would had worked!
This is not really a ‘bug’ because it is predictable, but it is very tricky and likely to generate a buggy behavior in your code if you don’t know… And it might be the same with ‘and’ when the first part of the statement is false. Take care!

Hello @Jmv38. What you are describing could be characterised as a useful, and documented, feature of Lua.

Hi @Mpilgrem. Hem, is it me or is there a little mix of irony and irritation in your feedback? :wink:
Well you are certainly right, but for newbes-who-dont-know-the-doc-by-heart (myself…) this useful feature can act as a trap, because in the other languages i know the ‘or’ is commutative (ok Andrew, i agree the lua operation is commutative from the strict point of view of the boolean result of the operator, but i mean in the wide sense: changing the order of the operands changes the results from the program point of view). I am sure some other people have made the same stupid mistake as me, and not found the root cause yet, so this post was simply to call their attention to a side effect of this useful and well documented feature.
Cheers.

To my best knowledge at least these languages implement the same operator shortcut behavior:

  • Python
  • Tcl
  • Perl
  • Lisp
  • C/C++
  • Go
  • Smalltalk
  • Java
  • Javascript

Famous Perl idiom:


eval($code) or die("Problem with some code");

.@Codeslinger Wow, i did not know it was the case for all these languages (and i’ve programmed in 4 of them… Freezes my spine! :frowning: :frowning: :frowning: ). So i am probably the only one who had this problem. Sorry for jamming the forum with this subject…

Don’t be sorry, I think it will surely help somebody. Anyway, this problem is common and guides for safe programming usually forbid the usage of “or” and “and” if parts of the expression have side effects.

I also found a natural language example: Don’t you dare! Or else …

The page on the wiki here may help others in the future.

.@Mpilgrem you know what? Now that i have understood this feature, i think it is a really useful one and i use it a lot! Because i can check for nil before calling a field: if a and v[a] then ... it makes the code more concise without clarity loss. Thanks for pointing this out.

It is useful for setting default values in classes as well:

SomeClass = class()

function SomeClass:init(x, y)

    -- if x is nil then self.x = 5
    -- that way when you initialise your class you can call
    --
    -- someClass = SomeClass() 
    --
    -- or you could set the values yourself:
    --
    -- someClass = SomeClass(8, 16)

    self.x = x or 5
    self.y = y or 10

end

```

.@Reefwing Yeah I’ve done that I usually have a nil clause in my conditions.