hcl
hcl copied to clipboard
No support for optional blocks
I'm writing a program where I have a large amount of config where the defaults are fine and don't need to be explicitly specified by the end user; I'd like to be able to do e.g. hcl:"Policies,block,optional"
and have hclsimple be fine with that block not being present.
@pontaoski You can have optional blocks if you use a struct pointer for the property type.
Policies *PoliciesConfig `hcl:"policies,block"`
Making everything pointers in order to have an optional type in config is less than ergonomic, IMO
I agree with @pontaoski that having to define an optional block with pointers is less than ergonomic and, in some cases, impractical when using third party libraries that generate structs such as entgo.io
gohcl
is generally designed to be used with structs that are written specifically for HCL, rather than structs written for other purposes and then annotated with hcl
tags.
A relatively common pattern with gohcl
as it exists today is to declare a local struct type inside your decode function and then transform it into whatever your broader application wants before returning:
func decodeConfig(body hcl.Body) (*Config, hcl.Diagnostics) {
type HCLPoliciesConfig struct {
// ...
}
type HCLConfig struct {
Policies *HCLPoliciesConfig `hcl:"policies,block"`
}
var config HCLConfig
diags := gohcl.DecodeConfig(body, nil, &config)
if diags.HasErrors() {
return nil, diags
}
ret := &Config{}
// Populate ret from config...
if config.Policies != nil {
// assign policies settings into "ret" if set
} else {
// somehow mark in "ret" that policies wasn't set
}
return ret, diags
}
The local struct types here are therefore acting just as a concise way of describing the expected configuration structure using Go syntax, not as a way to avoid writing normal code to process the user's input.
HCL requires a pointer in this case because otherwise it would be ambiguous whether the block was omitted or whether it was present and contained the zero value for each of the nested fields. The gohcl
API is generally optimized for giving an application detailed information about what the user provided so it can respond precisely, and so indeed some of the design decisions could be classified as "unergonomic" in the sense that they are forcing you to deal with each of the possible inputs separately and be intentional about how to handle them.