Skip to content

Name resolution and shadowing#

CEL identifiers are lexically scoped. Inner bindings shadow outer bindings with the same name.

Resolution order#

When CEL encounters an identifier, it checks in this order:

  1. Macro iteration variables
  2. Input variables
  3. Type names and enum values

Macro variables shadow input variables#

Macro iteration variables take precedence over input variables.

// input: x = 100
[1, 2, 3].map(x, x * 2)
// result: [2, 4, 6] (list)

The macro variable x shadows the input variable x.

Nested macro shadowing#

In nested macros, inner variables shadow outer variables with the same name.

[1, 2, 3].map(x,
  [4, 5, 6].map(x, x))
// result: [[4, 5, 6], [4, 5, 6], [4, 5, 6]] (list)

The inner x shadows the outer x, so each inner map returns [4, 5, 6].

Use unique, descriptive variable names to avoid confusion.

[1, 2, 3].map(outer,
  [4, 5, 6].map(inner, outer + inner))
// result: [[5, 6, 7], [6, 7, 8], [7, 8, 9]] (list)

See also#

  • Map - List transformation macro
  • Filter - List filtering macro