I’ve been trying to understand why I’m getting an undefined variable error, even though the expression in question is surrounded by an if block that evaluates false. This only happens when the if block uses a host group.
$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if false %}{{ foo }}{% endif %}”
localhost | SUCCESS => {
“msg”: “”
}
$ ansible -i inventory.yml group2 -mdebug -amsg=“{% if groups.group1 %}}{{ foo }}{% endif %}”
localhost | FAILED! => {
“msg”: “The task includes an option with an undefined variable. The error was: list object has no element 0”
}
The foo variable is being referenced, even though it is inside an if block that evaluates false. This only occurs when I use groups.group1 in the if expression, AND I refer to the variable foo. Why is this?
lazy evaluation prevents the error until the variable is actualy
consumed, group1 is empty so [0] is pointing to 'the first host of a
list w/o hosts', so the error is correct, you just avoid it in the
first case because of the conditional.
lazy evaluation prevents the error until the variable is actualy
consumed, group1 is empty so [0] is pointing to ‘the first host of a
list w/o hosts’, so the error is correct,
I agree, and don’t contest this part. If foo is evaluated it should raise an error.
you just avoid it in the first case because of the conditional.
T his part confuses me. I both cases the if condition evaluates false. So why is foo evaluated in one case but not the other?
Further info: I believe the behaviour I’m seeing is dependent on the version of Jinja2. If Jinja2 2.8 is installed then the “{% if false %}” case prints “”, and the “{% if groups.group1 %}” case raises the error. If Jinja2 2.9 or Jinja2 2.10 is installed then both cases raise the Error. This is based on testing across Ansible 2.7.{0,5,6,7,8,9,10} using Tox.
Most languages will not continue evaluation of all the components in a boolean expression once enough have been evaluated to determine the answer.
It’s obvious that in “if A and B then C”, C will only get evaluated if both A and B are true. But most languages will not bother evaluating B if A is false, because if A is false, then “A and B” must be false too; there is no point evaluating B, because it can’t alter the overall value of “A and B”. In such languages, B will only get evaluated if A is true, because only then might evaluating B change the value of the overall expression.
Similarly, in “if A or B then C” there is no point evaluating B if A is true, because if A is true, “A or B” is true too. It doesn’t matter whether B is true or false. However in this situation, B will only get evaluated if A is false, because only in that case might evaluating B change the value of the overall expression.
I.e., the order of the subexpressions in a boolean expression can be important. Sometimes it is useful. A very common idiom in lots of languages is “test and use” - if the test fails, the use never happens.