Variable Scoping in Nested Generates¶
When you move <variable> declarations from an outer <generate> into a nested <generate>, the XML often still looks valid, but the evaluation context changes. This page explains what the runtime actually does, why expressions like voszData.data[index] can start failing or reading the wrong frame, and which prefixes are safe.
Snap Summary¶
- Each nested
<generate>iteration runs in its own context frame. - In nested frames,
this.*is the stable way to reference variables declared in the current generate.
How DATAMIMIC Builds Scope Frames¶
Each <generate> iteration creates its own scope frame with:
current_variables: values created by<variable>current_product: values already written by<key>or nested childrencurrent_name: the current<generate name="...">
The important consequence is:
- The first
<generate>directly below<setup>is flattened into the top-level namespace. - A nested
<generate>is added under its ownname. - The current frame is always available through
this. - In nested frames, the merged direct parent view is available through
this.parent.
The Rule That Trips People Up¶
Inside a nested <generate>, an unqualified name does not reliably mean “the variable declared right here”.
It often resolves against the flattened ancestor frame instead.
That is why this can break after moving variables inward:
1 | |
If voszData and index used to live in the outer frame, that expression reads the outer values. After moving them into the nested frame, the unqualified expression may still resolve to the outer frame, not the new local one.
Use this instead:
1 | |
Quick Decision Guide¶
Use this shortcut when writing or reviewing expressions:
| You want to read... | Use... |
|---|---|
A variable declared in the current nested <generate> |
this.varName |
| A variable from the direct parent generate | this.parent.varName |
| A variable through an explicit named path | child.grand_child.varName |
A variable in the first generate below <setup> |
usually varName |
Tip
If you are unsure, prefer this.*. It is the clearest and safest choice for local nested variables.
Reference Table¶
| Where the value is declared | Preferred reference | Notes |
|---|---|---|
Current nested <generate> |
this.varName |
Most stable form |
Current nested <generate> |
<currentGenerateName>.varName |
Works for nested generates that are already inside another generate |
Direct parent <generate> |
this.parent.varName |
Explicit and safe |
| Flattened outer frame | varName |
Can work, but is easy to misread |
| Nested path already built in the current tree | child.grand_child.varName |
Useful for explicit tree access |
First <generate> directly under <setup> |
varName or root.varName |
Usually not available as root.generateName.varName |
Example 1: Moving Mem Variables Into the Inner Generate¶
Works when variables stay in the outer frame¶
1 2 3 4 5 6 7 8 9 10 11 12 | |
Here voszData.data[index] resolves against the outer frame, so it works.
Fails or reads the wrong frame after moving the variables inward¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Guidance
- Use
this.*when the variable is declared in the same nested generate. - Use
this.parent.*when you intentionally want the outer frame. - Avoid leaving the expression unqualified after moving variables across frames.
Example 2: Cascade Generate and this.id¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
Why this.id matters:
- Outer
idcan stay unqualified because that frame is flattened. - Inner
idvalues should be qualified withthis.to avoid shadowing confusion. - Reusing names like
id,index, orrowacross levels is safe only if you stay explicit.
Example 3: Named Path Access Across Nested Generates¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
This shows the current namespace tree, not a generic “any ancestor by name” rule:
child.idxworks becausechildis the flattened parent frame.child.grand_child.indexworks becausegrand_childis nested under that frame.this.indexis still the clearest way to say “the variable from the current generate”.
Example 4: nestedKey Pathing Is the Same Idea¶
nestedKey pathing uses the same mental model: you address values through the currently available tree instead of assuming “nearest name wins”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
Conceptually:
datais the named generate frame.send_infois a nested structure below it.contact_method.Emailis resolved through that explicit path.
The same advice applies to nested generates: prefer explicit paths when a value is not obviously local.
Example 5: Shared Variables Outside, Local Variables Inside¶
This is where the scoping model becomes useful rather than confusing.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | |
Why this is useful:
customerstays outside because both nested generates need it.- Each nested generate can still have its own local
lineIndex. this.lineIndexmakes it obvious that the value is local to the current nested generate.- Reusing the same helper name in two nested generates stays readable when you qualify it.
Why This Model Is Flexible¶
This scoping model gives you two useful patterns:
- Shared outer variables: Declare lookup data, memstore-backed values, or common IDs once in an outer generate and reuse them in several nested generates.
- Local inner variables: Keep helper counters, temporary selectors, or formatting values inside the nested generate where they belong.
The result is a model that stays explicit:
- Shared values stay shared.
- Local values stay local.
- Nested paths stay readable.
- Shadowing becomes manageable when you use
this.*consistently.
Best Practices¶
- Prefer
this.*for variables declared inside the current nested generate. - Prefer
this.parent.*when you intentionally read from the direct parent frame. - Keep shared memstore-backed variables in the outer generate if several nested generates need them.
- If variables are local to one nested generate, keep them local and use
this.*consistently. - Avoid reusing names like
id,index,row, ordataacross levels unless you always qualify them. - Treat unqualified names inside nested generates as risky, even if they currently work.
Troubleshooting¶
| Symptom | Likely cause | Fix |
|---|---|---|
variable not found |
The value exists only in the current nested frame, but the expression is resolving elsewhere | Use this.varName or <currentGenerateName>.varName |
| Wrong value but no error | The expression resolved to an outer flattened frame | Qualify with this.* or this.parent.* |
ambiguous variable or confusing shadowing |
The same name exists in more than one frame | Rename the variable or qualify the frame explicitly |
| Path works in one level but not another | The namespace tree shape changed after nesting | Switch to this.* for current values and explicit named paths for tree access |
root.someGenerate.var fails |
The first generate under <setup> is flattened, so that generate name may not exist under root |
Use root.var or the current in-scope named path instead |