Skip to content

Instantly share code, notes, and snippets.

@gilzoide
Last active December 16, 2023 12:33
Show Gist options
  • Save gilzoide/6d7c435e4585f8ba96592f89f2442845 to your computer and use it in GitHub Desktop.
Save gilzoide/6d7c435e4585f8ba96592f89f2442845 to your computer and use it in GitHub Desktop.
Logical XOR in lua
-- Returns false if value is falsey (`nil` or `false`), returns true if value is truthy (everything else)
function toboolean(v)
return v ~= nil and v ~= false
end
-- Returns true if one value is falsey and the other is truthy, returns false otherwise
function xor(a, b)
return toboolean(a) ~= toboolean(b)
end
@emilia-ghdt
Copy link

you misspelled boolean

@gilzoide
Copy link
Author

Oh my!
Thanks for noticing, I'll fix it right now xD

@KevinTyrrell
Copy link

KevinTyrrell commented Dec 16, 2023

The not keyword in Lua forces nil to true, meaning you can avoid the slower function overhead by doubling up not calls and inverting the equality. This should be as fast as you can possibly get it unless I'm mistaken:

function xor(a, b)
   return not (not a == not b)
end

@gilzoide
Copy link
Author

Oh, I guess you're right, thanks for the tip! In that case, I guess not a ~= not b would also work and is a bit clearer to the reader.

@KevinTyrrell
Copy link

Oops, wrote false instead of true above, fixed now. Also don't know why I thought nesting the not outside was necessary as just inverting the equality is equivalent.

Unfortunately both the above and the not approach fail on 0 and 1 since Lua considers both 'truthy' values. Anything outside of nil and false are truthy and therefor not 0 evaluates to false. For anyone finding this gist on search engines like I did, for numbers use bit.bxor instead from the standard library.

@gilzoide
Copy link
Author

Unfortunately both the above and the not approach fail on 0 and 1 since Lua considers both 'truthy' values.

That's not failing, this is just how Lua behaves. I labeled this gist "logical xor" because it follows Lua's boolean logic, which is exactly what I needed at the time.

But it's easy enough to patch toboolean and have a version of xor that considers 0 as false, if anybody ever needs it:

function toboolean(v)
    return v ~= nil and v ~= false and v ~= 0
end

function xor(a, b)
    return toboolean(a) ~= toboolean(b)
end

It's also easy enough to inline the toboolean operation into xor as well, although I'd say that's a microoptimization and won't matter in most use cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment