For human-maintained config, TOML is only "better" when the structure is so flat that it's almost indistinguishable from an INI file.
Anything more complex and it becomes one of the worst choices due to the confusing/unintuitive structure (especially nesting), on top of having less/worse library support.
YAML's structure is straightforward and readable by default, even for fairly complex files, and the major caveats are things like anchors or yes/no being booleans rather than the whitespace structure. I'd also argue some of the hate for YAML stems from things like helm that use the worst possible form of templating (raw string replacement).
I'm with you on all that. I think YAML's fine, and I like it way more than TOML for non-trivial files.
I think Python's pyproject.toml is a great use of TOML. The format is simple with very little nesting. It's often hand-edited, and the simple syntax lends itself nicely to that. Cargo.toml's in that same category for me. However, that's about as complex of a file as I'd want to use TOML for. Darned if I'd want to configure Ansible with it.
Agreed, I do a lot of Ansible, and it took me a while up front, but I've become pretty accustomed to YAML. Though I still struggle with completely groking some of the syntax. But, I recently took a more serious look at TOML and felt like it'd be a bear for Ansible.
A few months ago I made a "mini ansible / cookie cutter" ( https://github.com/linsomniac/uplaybook ), and it uses YAML syntax. I made a few modifications to Ansible syntax, largely around conditionals and loops. For YAML, I guess I like the syntax, but I've been feeling like there's got to be a better way.
I kind of want a shell syntax, but with the ansible command semantics (declarative, --check / --diff, notify) and the templating and encryption of arguments / files.
> For human-maintained config, TOML is only "better" when the structure is so flat that it's almost indistinguishable from an INI file.
Agree. I've recently inherited a python project, and I'm already getting tired of [mentally.parsing.ridiculously.long.character.section.headers] in pyproject.toml.
Seriously, structure is good. I shouldn't have to build the damn tree structure in my head when all we really needed was a strict mode for YAML.
> I'd also argue some of the hate for YAML stems from things like helm that use the worst possible form of templating (raw string replacement).
I was literally speechless when I saw helm templates doing stuff like "{{ toYaml .Values.api.resources | indent 12 }}", where the author has to hardcode the indentation level for each generated bit of text like a fucking caveman.
The tiny examples might look kinda okay, but when someone has stacked 10 different patch operations in a single file, it gets a lot harder to keep track of what's going on.
“Nesting is bad” is such a simplistic take. Nesting is absolutely essential and inescapable. What that statement is really doing is placing a limit on what whatever it applies to can be used for. It would be better to spend a few more words expressing what you really mean.
Your comment is a simplistic take on "Nesting is bad" given the context.
It's not hard to infer that they're referring to nesting as a footgun: make it harder and you lose some power but you keep your feet.
Config files are a poor place to complex and deeply nested relationships. If it's not ergonomic to reach for nesting people tend to be forced to rethink their approach.
The problem is "config" means different things to different people. Some people see config as "the collection of runtime parameters" basically a bank of switches: Pyproject.toml is config. Others see any form of declarative structured data ingested by a runtime as config: docker-compose.yml is config.
And of course to minimize impedance mismatch, the structure should be similar to the domain.
So yes I want a "config file" to handle at least a dozen levels of nesting without getting obnoxious.
Then I guess to frame it in your language: they want formats that encourage config files, not "config files".
And I don't disagree. The problems of nesting objects "at least 12 levels deep" aren't going to be solved by the right format. The tooling itself needs to expose ways to capture logical dependencies other than arbitrary deep K-V pairs.
What if your problem is best expressed as "arbitrary deep K-V pairs"? It's going to be more common than not, nesting really is that fundamental.
There is no escape, you can't win. If you want the nesting, and assuming you can't remove it from the problem itself (as you often can't, or at least shouldn't), there's only one thing you can do: move inner things out, and put pointers in their place. This is what we do when we create constants, variables, and functions in our code: move some of this stuff up the scope, so it can be used (and re-used) through a shorthand. It loses you the ability to see the nesting all at once, but is necessary (among other reasons) when the nesting is too large to fit in your head.
Of course once you do that, once you introduce indirection into your config format, people will cry bloody murder. It's complex and invites (gasp) abstraction and reuse, which are (they believe) too difficult for normies.
The solution is, of course, to ignore the whining. Nesting is a special case of indirection. Both are part of the problem domain, both are part of reality. Normies can handle this just fine, if you don't scare them first. You need nesting and you need means of indirection; might as well make them readable, too. Conditionals and loops, those we can argue about, because together they give a language Turing-complete powers, and give security people seizures. And we have to be nice to our security people.
This is whining that people won't endorse a lazy, poorly scaling approach to an engineering problem... and justifying that approach by conjuring hypothetical whiners against a common, better scaling solution.
If you need 12 levels of nesting, add indirection, or live with the fact no one is designing formats to enable your oddball mess of a use case.
12 levels of nested braces in a single function is already a crappy idea: it's an even more crappy idea in a config file because of the generally inferior tooling, and now there's a downstream component that needs to change to support a cleanup (meaning it almost never gets fixed and the format just gets worse over time)
Anything more complex and it becomes one of the worst choices due to the confusing/unintuitive structure (especially nesting), on top of having less/worse library support.
YAML's structure is straightforward and readable by default, even for fairly complex files, and the major caveats are things like anchors or yes/no being booleans rather than the whitespace structure. I'd also argue some of the hate for YAML stems from things like helm that use the worst possible form of templating (raw string replacement).