-
Notifications
You must be signed in to change notification settings - Fork 257
feat: Add writer settings to enable collection sorting using a comparer #2363
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
feat: Add writer settings to enable collection sorting using a comparer #2363
Conversation
I'm pretty sure that ASP.NET does not want all dictionaries to be sorted when a comparer is provided, according to this comment. A similar concern applies to Swashbuckle. Once collections (and not just dictionaries) are interfaces again, ASP.NET can initialize with a sorted collection at the places where sorting is desired. And in case |
@bkoelman The primary goal of sorting the collections is to provide a deterministic order. Not sorting all of them would risk non-deterministic ordering. Obviously this approach is not going to suit everyone. Ordering using the writer settings is opt-in and now that everything is back to interfaces, based on your feedback, developers are free to provide implementations with specific ordering characteristics. |
First of all, thanks for reverting back to collection interfaces. This unblocks mine and other projects.
But the order is already deterministic, right? To the best of my knowledge, it has always been in this library, without the need for sorting support. This is because
I understand that using the writer settings is opt-in, and I'm happy with that. It's just that I can't think of a scenario where anyone would ever want to use it, given the way it is implemented in this PR: it's an all-or-nothing switch. Once a comparer is provided, then all dictionaries everywhere get sorted, which is what truly nobody wants. I'm just alerting that likely a useless feature is being added, possibly due to miscommunication with others. This won't help ASP.NET or Swashbuckle in any way, because they want to preserve declaration order for C# properties. They do want to sort the list of component schemas, but with the all-or-nothing comparer support provided here, they can't use that. This is because the methods |
@bkoelman Here is a concrete example where we need to be able to sort path objects by path: Specifically: In this PR, the Catalog service adds a new API version while the previous version should be unchanged. But the diff shows 602 lines changed. ![]() This is almost entirely because of reorderings, e.g. the "/api/catalog/items/by" path was originally ordered after "/api/catalog/items", but the changes cause it to now be ordered before "/api/catalog/items". ASP.NET does not document the order in which endpoints are added to the document and developers should not depend on this ordering. So to achieve a deterministic ordering we want to emit the paths objects ordered by path. |
@mikekistler Thanks for providing a use case. Again, this is about sorting paths only. Not about sorting everything in the document. For example, the This example essentially reinforces my point that providing a comparer won't solve the problem. |
Dismissing this as all feedback is implemented and this needs to be merged.
@bkoelman Appreciate you pushing on this. I understand this is an edge case but C# dictionaries are not deterministic. From the docs:
@mikekistler If the properties dictionary in schemas are sorted is that going to be concern for you? |
Oh yeah, I'm well aware of that. In my early days I implemented my own collection types with stronger guarantees. Until after a few years I realized almost every .NET app indirectly depends on this implementation detail. The same applies to the CLR memory model, whose implementation has way stronger guarantees than documented, and systems have taken a dependency on it. A few years back, those docs were updated to match the implementation, after ARM support was added that initially didn't provide the same guarantees, and everything broke. And let's not forget that various improvements in .NET Core were reverted after a few releases when customers started reporting their .NET Framework code didn't work anymore. For example, that So I wouldn't worry about this for a second. This library was been deterministic for many years. If that weren't the case, it would have surfaced, because OAS files are typically under source control in consuming systems. That is, because Swashbuckle uses sorted collections in some places, which aspnet can also do already. |
Assuming that Mike's code relies on aspnet doing the sorting, confirm with @captainsafia, who has already indicated that sorting will not be applied to properties, but will only be applied to components here:
|
@darrelmiller I'm afraid it will be a problem if the properties in schemas are sorted lexicographically. There may just a few other cases where we don't want lexicographic sorting. Others I can think of:
In short, I think we would like a solution that lets us sort the things we want sorted, but leave alone things we'd prefer to leave in their "natural order". For example, if we could provide a set of comparers on OpenAPI object types, e.g. |
@mikekistler @bkoelman would that work for you if instead of having a single comparer, we had a bunch of named comparers in the settings? (e.g. PathSortingComparer, ComponentIdsSortingComparer, SchemaPropertiesSortingComparer, etc...) this way everyone gets granular control over what they want to sort? And if new collection arise from the standard, adding new comparers is additive (no breaking changes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM besides the ongoing discussion about the desired behaviour
|
I think something like this will work for ASP.NET. I'm not sure why these have to be named comparers, as I think it could be just a set of comparers that holds generic |
Unfortunately, it's not that simple. Let's take an enum, which can be defined at various depths in the tree, ie, inside a Besides that, only string comparers make sense (used for dictionary keys). A comparer on an I'm happy to see that this PR has been merged, because the interfaces unblock all use cases, as far as I'm aware. I recommend hiding the comparer support for the next .NET 10 preview release. As far as I understand it, ASP.NET won't benefit from their presence, but the good news is that they can now do whatever's needed themselves, since interfaces are back. We're merely guessing at what the true concerns are for ASP.NET, so I think a conversation with the team should happen first, before releasing something that hasn't been fully thought through. |
OpenApiWriterSettings
options to meet the need for deterministic ordering as per this comment:1.
EnableSorting
to enable sorting dictionary keys using a default comparer2.
KeyComparer
to allow consumers to plugin a custom comparer to sort dictionary entriesFixes #2329