-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
YAML output record fields in order for readability #1187
Comments
@JohannesRudolph: The main issue here is that the conversion to YAML is conceptually done in two steps:
... and the standard requires that normalization sorts record fields (See: dhall-lang/dhall-lang#223), so even before the YAML-specific logic begins the record fields are already sorted. Using the current Haskell API, there is currently no way to preserve field order when normalizing expressions. Fixing the API to support that, is possible, but would be an invasive change and significant departure from the standard so I want to ensure that there is a compelling reason to do so first. In this particular case, the main thing I want to understand is why the generated YAML file is checked into version control since it's a derived build product from the Dhall configuration. By storing both in version control you permit an invalid state to be representable (where that invalid state is the two files being out of sync). Or to make an analogy, I believe you would not want to version control the derived YAML file for the same reasons that you don't version control binary artifacts of your build process and you instead only version control the original source code. |
@Gabriel439 Thanks for the fast response! I highly appreciate your support here and on SO and admire all the hard work you (and many others!) have put into dhall. It's clearly a smart take on configuration and so far I really like it! We’re evaluating whether we can use dhall to generate configuration for a bunch of apps + corresponding concourse ci pipelines and tasks. This would add a great deal of safety to our delivery pipelines that need to cover a range of different environment and deployment targets. Concourse for example is not able to read dhall natively In any way, it only supports yaml stored in a repo for tasks. I agree that it’s not the optimum way and the sync issue is something to beware of. However, I think for configuration the situation is not as clear cut as it is for source code:
I would assume that Dhall will often be used in "brownfield" contexts, i.e. our particular evolution of problems and tooling choices as our product continues growing looked like this:
So in the brownfield context being able to "gradually" introduce dhall is somewhat important, e.g. we want to start by replacing some of our old ejs yaml generators with dhall. And it's easy for us to ensure we don't break things in the process when we can just review the generated yaml in our git PRs. I hope that shed's some light into our experience with dhall so far and gives you a real-world data point on potential users ;-) And I must admit that I really like that I finally have a good excuse to do some haskell-y things at work! |
After that long monologue above I realize I actually forgot to get back to the point 😅 So in essence, I consider ordered yaml keys very useful. I bet dhall-kubernetes users will feel similar (e.g. its customary to have
So there must be some sort order defined... right? (btw. I couldn't figure out what sort order it actually is). Why couldn't that normalized sort order be the order defined in the type definition? Of course that implies that changing the sort order in a type definition changes the normalized form and the semantic integrity hash changes? Is that something that would kill compatibility? |
Keys are sorted according to In my dhall-purescript project, I essentially have forms of normalization that do change the order of keys, which are used for comparisons (e.g. What happens in that case is that a {record,union} {literal,type} has each of its fields normalized but its order is not changed. That is, it is simply mapped or traversed to obtain the new value. The order of a record literal going in is its order going out, the type has nothing to do with it. (And when it needs to be sorted, the appropriate transformation is run over the AST to sort those cases.) Now, you have to decide on an order for operations like Anyhow, I imagine standardizing this behavior would be possible, if the idea is favored. |
@JohannesRudolph at work we went through exactly the same "brownfield" process that you described. To keep the configs "auditable" and "debuggable" we just print the rendered YAML/JSON/etc to the CI logs (so that if we want to take a look and/or replicate we can), but only the Dhall code is versioned. We do use dhall-kubernetes, but the field ordering has never been a problem because we don't look at the YAML at all - because if it typechecks then it's good to be sent to Kubernetes 🙂 Though in some other cases I felt that ordering the rendered YAML would have been nicer/clearer/etc, but I think that if we want to implement this "rendering order" then there's a simple-but-maybe-not-perfect way; we could:
This can be done in the |
@f-f: That won't work in general because the records might be computed and might not be present in their entirety in the original syntax tree parsed from the file. For example: let x = { foo = 1 }
let y = { bar = True }
in x ∧ y The only way to guarantee getting the complete record is to normalize the expression, but that will sort the fields along the way. However, I think I will go with the approach that @MonoidMusician suggested (to parametrize the expression type on the key-value type constructor), since I will need to do that anyway to fix #772, too. |
I know it probably sounds very naive but wouldn't it be possible to export a A straightforward implementation could be to start with |
@antislava: The main thing that makes it tricky is the API's support for custom normalizers. You'd have to thread the sorting decision throughout the code in a lot of places. I'm currently trying to clean up how the API supports customization to make this easier to do |
I'm going to move this issue to the |
@JohannesRudolph saw this once Gabriel bumped the topic by moving it into This is still an issue in the general case, but thankfully not for Concourse. |
A possibly simpler approach would be to perform the field sorting as a separate step after normalizing everything else. I believe that would be fairly simple to implement, but possibly less efficient than the parametrization. |
I believe that the departure from the existing Dhall-JSON-YAML pipeline discussed in #1435 could help us preserve the order of fields when translating Dhall to YAML. |
wondering if this is in the roadmap-- It would be a helpful function on my end, as I'm hoping to use dhall to yaml for readability/documentation. |
We don't have an official roadmap. It's mainly whenever one of us can get around to this Part of the delay is that this particular change requires pretty sweeping changes to the codebase to implement |
Suppose I have the following record definitions:
When I run such a value through
dhall-to-yaml
, I get a YAML that looks like thisUnfortunately the reordering of yaml fields compared to the record definition makes these files a little less readable. Ideally, dhall-to-yaml would have a mode that allows for preservation of field order to make generated yaml a little more human-friendly. This is important when I want my generated YAML to match established conventions or replace existing hand-built YAML with dhall-generated ones without creating crazy diffs. Of course, yaml key order is not important semantically, so this is just about humans reading it.
The text was updated successfully, but these errors were encountered: