walk-no-path
Summary: Call to walk
can be optimized
Category: Performance
Avoid
package policy
import rego.v1
allow if {
# traverse potentially nested permissions structure looking
# for an admin role, but notice how the path is never referenced
# later
walk(user.permissions, [path, value])
value.type == "role"
value.name == "admin"
}
Prefer
package policy
import rego.v1
allow if {
# replacing `path` with a wildcard variable tells the evaluator that it won't
# have to build the path array for each node `walk` traverses, thereby avoiding
# unnecessary allocations
walk(user.permissions, [_, value])
value.type == "role"
value.name == "admin"
}
Rationale
The primary purpose of the walk
function is to traverse nested data structures, and often at an arbitrary depth.
Each node traversed "produces" a path/value pair, where the path is an array of keys that lead to the current node,
and the value is the current node itself. Most often, rules only need to account for the value of the node and not the
path, and when that is the case, using a wildcard variable (_
) in place of path tells the evaluation engine that
there's no need to build the path array for each node traversed, thereby avoiding unnecessary allocations. This can
have a big impact on performance when huge data structures are traversed!
More concretely, walk
ing without generating the path array cuts down evaluation time by about 33%, and reduces the
number of allocations by about 40%.
Trivia: this optimization was originally made in OPA to improve the performance of Regal, where walk
is used
extensively to traverse the AST of the policy being linted.
Exceptions
This rule can only optimize walk
calls where the path/value array is provided as a second argument to walk
, and
not when assigned using :=
:
package policy
import rego.v1
allow if {
# this can't be optimized, as the `walk` function can't
# "see" the array assignment on the left hand side
[path, value] := walk(user.permissions)
value.type == "role"
value.name == "admin"
}
For this reason, and a few historic ones, using the second argument for the return value is the preferred way to use
walk
, which is unique for the walk built-in
function.
Configuration Options
This linter rule provides the following configuration options:
rules:
performance:
walk-no-path:
# one of "error", "warning", "ignore"
level: error
Related Resources
- Regal Docs: function-arg-return
- GitHub: Source Code
Community
If you think you've found a problem with this rule or its documentation, would like to suggest improvements, new rules,
or just talk about Regal in general, please join us in the #regal
channel in the Styra Community
Slack!