Use the same function call in each conditional statement
See the warning
Expected Behavior
Functions that are non-deterministic or read from global variables should not be considered “repeated” even if they are called identically in an else-if chain.
Actual Behavior
When writing else-if chains in Luau with strict mode enabled, repeated non-deterministic function calls (such as math.random()) are incorrectly considered identical statements.
See this example:
Issue Area: Studio Issue Type: Other Impact: Low Frequency: Constantly Date First Experienced: 2021-08-25 00:08:00 (-05:00) Date Last Experienced: 2021-08-25 00:08:00 (-05:00)
Yeah it’s not clear how we can fix this to me. We could special-case math.random but that doesn’t seem reasonable to do. We could stop emitting this warning if we see function calls, but that is actually counter-productive in that it stops catching copy&paste errors in many common cases such as if foo:IsA("Part") then ... elseif foo:IsA("Part") then ... end
FWIW if this is an example from actual production code you can always rewrite it as:
local r = math.random()
if r > 0.5 then
...
elseif r > 0.25 then
...
else
...
end
which won’t trigger this warning but also makes it more obvious as to what the probabilities of individual cases are.
There is a list of the warnings which can be produced and their names on the Luau website, and it describes how to disable them (--!nocheck, --!nolint NAME, and --!nolint).
The only way I can think of for Luau to solve this problem precisely would be to recursively check the function for a read from any variable defined outside the function’s scope.
A close approximation would be to add compiler annotations to all built-in Roblox functions to tell it whether to consider a particular function deterministic or not. Then assume all non-annotated functions are non-deterministic by default. That would take care of the math.random() and foo:IsA("Part") examples.
It won’t because it assumes you always know that foo is an Instance which will only work in type-annotated or strict code. In practice it’s very difficult to guarantee any determinism especially given the existence of metatables which means even if foo.X then elseif foo.X then end is potentially running non-deterministic code during two evaluations of .X