Hi again all!
As you can see in the chatter above, @lorengordon’s question about our handling of null values made us realize that our team didn’t have a shared understanding of what we’d designed and what was implemented.
This is a great example of why we like to share work in progress in these alpha releases and react to your questions and feedback, so thanks for drawing attention to that!
Since then we’ve been reviewing some of the use-cases that motivated this feature, and reviewing similar behaviors elsewhere in Terraform. Based on that we’ve made a small design change in today’s v1.3.0-alpha20220817 release which will make Terraform treat a null value in the way I described in my earlier incorrect comment.
Specifically, if an attribute has a default value specified then Terraform will use that default value both when the attribute is entirely omitted by the caller and when the caller explicitly sets it to null.
We’ve made this change to support the established patterns for dynamically deciding to leave an optional attribute unset. The simplest form of that is a conditional expression where one of the result arms is null:
example = {
foo = var.predicate ? "foo" : null
}
There are other similar situations that don’t involve conditionals, but the above is the most common technique.
The general idea is to make the two mechanisms involved here work independently of one another:
- An optional attribute means that Terraform will synthesize a null attribute of the appropriate type when converting a source object that omits that attribute.
- Specifying a default means that Terraform will replace a null value with the given default value after type conversion is complete, regardless of why the attribute turned out to be null.
This then matches how Terraform treats optional arguments in resource blocks: Terraform Core handles the conversion to the given object type and then the provider replaces any null value with its default value.
We’ve done our best to try to identify potential real-world situations where it would be important to distinguish an explicit null value from an null value implied by omission, but we didn’t find any compelling examples in our analysis so far.
We’d love to hear from you if you try the new behavior in the latest alpha and find any specific real-world situations where being unable to recognize this difference is problematic.
In response to any examples we will first try to imagine a different way for you to model the situation using this updated design. If we cannot find a reasonable answer then we still have some time to adjust the design further before including it in the final v1.3 release, or to convince ourselves that the need could be addressed by a backward-compatible addition in a later release.
This comment is already far too long so I won’t go into the details here, but we do have sketches for some different ways to extend the attribute declaration syntax with more features in a backward-compatible way, and so the door is still open for more detailed constraints in later versions.
Thanks again for trying this out and sharing your feedback!