-
Notifications
You must be signed in to change notification settings - Fork 22
Description
Describe the bug
Based on documentation (emphasis mine):
Values [of environment variables] may refer to other local environment variables (order of definition is preserved)
Cylc uses OrderedDict to store configuration items in their definition order. However, when combined with family inheritance the resulting order can be surprising (from the the user perspective), i.e., the order of local definitions can be violated.
Steps to reproduce the bug
Consider the following example:
[scheduling]
[[dependencies]]
graph = task
[runtime]
[[FAM]]
[[[environment]]]
BAR = bar
[[task]]
inherit = FAM
[[[environment]]]
FOO = foo
BAR = ${FOO}
This will store environment of task as:
$ cylc get-config --sparse -i '[runtime][task][environment]' SUITENAME
BAR = ${FOO}
FOO = foo
Note that BAR variable is now before FOO, unlike in the user definition, which will lead to unbound variable error in the job script. The reason for this is the definition of BAR under FAM. Even though BAR is subsequently redefined under task, the order of variables is determined by their first assignment rather than the last.
So, if BAR is not defined under FAM, the suite works OK. Then, if at a later time one adds BAR under FAM (because it might be needed by some other task(s) inheriting from FAM), the suite suddenly breaks and it's not very intuitive why.
Expected behavior
I think the most intuitive (and sound) behaviour is to preserve the order of local definition under the environment section, i.e., follow the override order rather than the order of first definition, which might be somewhere deep within the inheritance hierarchy.
The fix is relatively trivial and was proposed in cylc/cylc-flow#3305 but rejected as unsuitable for a patch release.
Additional context
@hjoliver considers (cylc/cylc-flow#3305 (comment)) a variable to be defined by its (oldest) parent, not when it is overridden. I think that interpretation is quite debatable. I would argue that, when overridden, the variable is simply redefined, i.e., its definition changes. (In formal terms, binding a symbol (name) to a value forms its definition and thus rebinding the symbol to a different value redefines it.)