I use statically-typed programming languages, and for my purposes I'd rather have a config language where the only types are strings, arrays, and hashmaps, and then push all type validation into the parsing stage.
I use statically-typed programming languages, and for my purposes I'd rather have a config language where the only types are strings, arrays, and hashmaps, and then push all type validation into the parsing stage.
Having the ability to pull all that validation forward, and into your IDE, means you can be told about invalid config as you’re writing it. To me the idea of only wanting to validate config at the last possible moment, is a bit like advocating for only using simple text editors, and replying purely on build failures for feedback. Sure you can do it, but why would subject yourself to that?
Pkl is interesting because it makes it possible to describe not just the types, but also valid configs. Effectively allowing you to ship your applications config parsing and validation into Pkl, so your code can just expect valid config. Then Pkl can expose all that parsing and validation logic into your IDE, so you get pointers as you type. Just like you do in any modern IDE for any modern language.
Those languages that arrived with the JSON hype train like yaml or toml might be great for dynamic languages, where you can load them to some native object. But in statically typed languages you are gonna declare your types, in code, anyway. So configuration providing types doesn't really do much.
"Enough" is the keyword here, time will tell I guess.
Being able to use Pkl code-gen to create language bindings means you can take any arbitrary Pkl schema and turn it into native structures in your language, typed based on the Pkl schema. Then you can let Pkl do all the heavy lifting of parsing and validating a specific config, and turning it into native objects in your language.
So no need for double declaring types. Declare them once in Pkl, generate the equivalent types in your language, then just start using those types like any other primitive. The Pkl bindings will handle the loading glue for you.
I'm not hating on Pkl here, we deserve better in this space, so I'm happy with more developments.
But xml itself was not a good language for this, because its legibility is terrible. It's just not a good format for human reading and editing. (But it also isn't a great format for machine interaction either...)
So yeah, I see it as a good thing that this seems to be able to do all that useful stuff you were doing with xml and xsd a decade (and more) ago. But it's (IMO) a much nicer way to do it.
Sadly, nobody ever cared about that.
I think the problem might be separation of concerns...
pkl comes in early, and by design is separated from your app and the details thereof. It seems good for validating high-level or external configuration constraints. But suppose you have some constraints based on implementation details of your app. Now you face a choice: eschew pkl and put that validation logic in the app where you lose the benefits of early validation or put it in pkl (if that's even possible) which implicitly makes it dependent on application implementation details. Of course, we devs aren't great at stopping to consider the deep implications of each config param we add, so which one happens in practice in each case probably depends on the dev or dev group and how much they've bought in to pkl... some will pretty much always add a config to pkl because that's what it's there for, while others will ignore pkl whenever they can. I think this is inherent in the ambiguity the choice presents. There's probably a right choice in each case, but devs will only sometimes be that careful about the location of each config validation.
That's my guess anyway, as to why the previous post wants to just put all the validation at the level it's used. If that's your rule the ambiguity is resolved and it works perfectly for config dependent on specific app concerns and pretty well for config that also has high-level or external concerns, since those are less volatile and when they do change, it generally implies app changes in any case.
My gut says pkl is over engineered for the vast majority of cases and people should not reach for it unless they have a specific problem that it will solve for them.
E.g. so you always write valid k8s manifests.
And then you can extend them with your own additional validation rules for what you think your app needs? I’ve just skimmed the docs but it seems it allows you to be as loose or as precise as possible, plus packaging and publishing those rules for others to use.
Seems kinda awesome.
Helm isn’t a configuration language, it’s a dressed up string templating system with ability to do kubectl apply.
> you can't guarantee your config is valid anyway if your config language can't see what class you're going to feed it to.
Obviously, but that’s hardly an insurmountable problem. We’ve had code gen and language introspection for decades.
A config language that does have the type information can give proper errors. Try for example terraform.
The disadvantage of typed configuration languages is they make assumptions about the format of the data. For you a "date" type might mean ISO 8601, but for me it might mean RFC 3339. Config languages that make assumptions are coupling the language and schema validation together. The alternative is to decouple them: offer a flexible configuration language with a separate schema language. The latter would let you define the schema specifically for your data for validation.
A generic date type doesn’t come with any specific string format. ISO 8601 and RFC 3339 are both ways of representing a date as a string. Which has little to do with Date as a type.
There’s also perfectly good solutions to those problems. Use a type alias to create a date type backed by a string, with formatting constraints (such as a regex). Then people can define dates using any string representation they want!
Incidentally this is exactly what Pkl lets you do. You can use Pkl schema to define in detail how you want to validate your data using various primitives like regex. And then separately create a config template that uses those custom data types. As a dev you can choose how tightly bound your config template is to a data validation schema, define all the validation in line, or import an external module to provide you with richly validated data types.
Tell that to the TOML authors [1].
It's good Pkl has string validation, but what if I don't want a string? What if I want my own literal datetime syntax, like TOML? The grammar for a configuration language could be made flexible enough to accept most anything as a value. In such a design the "string" type itself could be a regex rule defined by a schema.
Keep in mind datetime literals are just an example, the actual number of potential types is unbound.
The near-compatibility of ISO 8601 and RFC 3339 is a rich source of bugs, but that's hardly TOML's fault, and the standard is perfectly clear that the latter is used. TOML, like many configuration and data transport languages, is defined in terms of its syntax, so an abstract Date type doesn't make sense for it.
Providing a datetime format for TOML was probably the right decision, I think there are more people who complain about JSON lacking one than there are who complain about TOML having one.
Where do you store the schema?
This becomes a lot more painful if your work is more polyglot. If you need to define config that needs to be shared between different applications, but they're written in different languages, you'll have a much harder time. Also, say, if you need to deploy your applications to Kubernetes, and your Kubernetes specification needs to provide config files to your application, then you'll still end up in a situation where your statically typed programming language won't help. That is where something like Pkl becomes really helpful, because you have just one place to manage all that complexity--right in Pkl itself.
- scalar value
- feature toggle
- URI/enum option/human readable display text
Having float/long/boolean is trivial to validate in the config language itself, and if they're useful and simple enough isn't it nice to be able to validate your config as early as possible?
Basically forcing everyone to learn new tooling (Pkl here, but lots of json/yaml middleware nonsense fits the bill too) just to deal with what really isn't that big of a problem seems like a bad trade.
Representing arrays as maps would impose no additional requirements outside of validation which is already considered as part of the proposal in question.
https://github.com/madmurphy/libconfini/wiki/An-INI-critique...