Last active
January 26, 2026 00:22
-
-
Save appgurueu/0a7c87ea6a8b18cbea477fba1949697d to your computer and use it in GitHub Desktop.
`pairs` order randomization
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| --[[ | |
| Slightly randomize `pairs` traversal in order to deliberately break most code that relies on it. | |
| Works by doing a coin toss to decide whether to "postpone" visiting the first entry | |
| (visiting it at the end of the traversal). | |
| Shuffling all keys, then iterating in that shuffled order would provide more thorough randomization; however: | |
| * It is less efficient if the loop is exited early; it may arbitrarily wreck asymptotics | |
| (consider a large table where `pairs` is only used to inspect very few entries.) | |
| * More sophisticated "on-demand" shuffling using appropriate data structures is possible, | |
| but increases code complexity and overhead significantly. | |
| * I believe this simple solution already suffices for most code | |
| that incorrectly relies on a specific order of traversal. | |
| Notably, this has a 50% chance of breaking code that | |
| expects `pairs` to exhibit `ipairs`-like behavior. | |
| This does not seed the random for you, | |
| so if you want to achieve different outcomes across different runs, | |
| seed the random yourself. | |
| ]] | |
| function pairs(tab) | |
| local fk = next(tab) | |
| local sk = nil | |
| if math.random(2) == 1 then | |
| sk = fk | |
| end | |
| local f = sk ~= nil | |
| local done = false | |
| return function(t, k) | |
| if done then | |
| return nil | |
| end | |
| local rk, rv = next(t, k) | |
| if rk == nil then | |
| done = true | |
| if f then | |
| f = false | |
| return fk, t[fk] -- note: reindex, t[fk] may have been modified during traversal | |
| end | |
| return nil | |
| end | |
| if f and rawequal(rk, fk) then | |
| f = false | |
| end | |
| return rk, rv | |
| end, tab, sk | |
| end | |
| -- Example: | |
| for i = 1, 10 do | |
| print(i) | |
| for k, v in pairs{a = 1, b = 2, c = 3} do | |
| print(k, v) | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment