Open joaocc opened 1 year ago
Thanks for these feature requests, @joaocc.
Some of these overlap with existing functions or language features, though not perfectly in all cases:
coalesce
is already essentially your proposed ifnullorempty
, except that it supports any number of arguments and just returns the first one that isn't null or an empty string. (It doesn't treat any other kind of "empty" as absent, so it's not a perfect analogy.)
I would prefer if coalesce
were more like your proposed ifnull
-- only skipping null values, not empty strings -- since that's closer to the SQL function that this was inspired by, but sadly coalesce
inherited this "empty string is the same as null" assumption from Terraform v0.11 and earlier and so we're now stuck with it for backward compatibility.
isempty(e)
seems to be equivalent to length(e) != 0
, and so doesn't seem to be necessary.In general I'm not a fan of features that would encourage treating null
and "empty" as the same, since that seems likely to confuse the meanings of those concepts. null
in Terraform represents the total absense of a value, which is intentionally a distinct idea from a non-null value that happens to be "empty" if such a concept is available for its type. This special meaning of null
is important because it's how Terraform represents the value of a totally-unset argument, allowing default values to be used instead, whereas "empty values" should not be treated in that way.
There are historical inconsistencies like the coalesce
function I mentioned above (which treats ""
the same as null
) and the default treatment of input variables (when they don't have nullable = false
set), but both of those design warts are things we'd like to fix in a future language edition and doing so will become harder if we introduce more features that persist that ambiguity.
Given all that, my own version of this proposal would be:
In a future language edition, make coalesce
only skip null arguments, and treat ""
as a normal value to be returned.
That would mean that coalesce(foo, "bar")
would be equivalent to what you proposed as ifnull(foo, "bar")
, but it would also be possible to write coalesce(foo, bar, baz, "fallback")
to take the first one that isn't null, just like the SQL function of the same name.
Consider a new function which takes a value of any type and returns null
if it's an empty string, empty collection, empty object, or empty tuple. This would be an "escape hatch" for when working with legacy or strange modules that use non-null empty values to represent "absent", and would then avoid the need for special additional functions to work with "empty" because you'd be able to combine the null-oriented ones with this new function.
I don't know yet what I'd call such a function. It's a little similar to our existing one
function except that it would work for more types and for collections/structures with more than one element. emptyasnull
seems like a plausible placeholder name for discussion:
coalesce(emptyasnull(foo), "bar")
, assuming that we'd also redefined coalesce
to only skip null, would be the same as your proposed ifnullorempty(foo, "bar")
.
emptyasnull(foo) == null
would be the same as your proposed isnullorempty(foo)
.
This is of course not as readable/convenient as having specialized functions that handle both cases, but for me that's intentional to help communicate that using non-null values to represent absence is an unusual thing to do, and thus to encourage using null
to represent the absence of a value in all cases.
With that said, we are also planning to introduce the ability for providers plugins to contribute their own functions to the Terraform language in a future Terraform version, and so at that point it would be possible in principle to write a provider that offers additional combinations, if you really want them. For the core language we try to focus on a single "main" usage pattern and then offer composable building blocks (as few as possible) to deal with situations that diverge from that main usage pattern, but provider developers will be able to make different design tradeoffs.
Terraform Version
Use Cases
The terraform language is quite rich and very powerful. However, for those accustomed to other similar languages, some useful functions could be added to make development life easier, and without breaking any kind of existing code. It does also allow the use of some development idioms that are currently out of bounds.
ifnull(expression, expression-to-return-if-null)
-> expressionifempty(expression, expression-to-return-if-empty)
-> expressionifnullorempty(expression, expression-to-return-if-null-or-empty)
-> expressionisempty(expression)
->true
if is "", [], {}isnullorempty(expression)
->true
if is null, "", [], {}Attempted Solutions
There are workarounds for them, but they are quite verbose, force expressions to be repeated (eg, when using ?: to do a ifnull) and/or are harder to manage
Proposal
Add the following functions to the library:
ifnull(expression, expression-to-return-if-null)
-> expressionifempty(expression, expression-to-return-if-empty)
-> expressionifnullorempty(expression, expression-to-return-if-null-or-empty)
-> expressionisempty(expression)
->true
if is "", [], {}isnullorempty(expression)
->true
if is null, "", [], {}References
No response