-
-
Notifications
You must be signed in to change notification settings - Fork 48
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
Add RFC for SortBy #178
base: main
Are you sure you want to change the base?
Add RFC for SortBy #178
Conversation
@damon-kwok can you expand the motivation to explain why, given the existence of Additionally as part the detailed design, you should note there that is an existing implementation at X location. That information is currently hidden in the "How we test". |
@SeanTAllen Updated. |
@damon-kwok "is not beginner friendly" is a statement. You need as part of your motivation to demonstrate how it isn't beginner friendly and how SortBy is. |
@damon-kwok I think the second argument is really the strong point here. "Beginner friendliness" is kind of arbitrary and may not be a point that you really want to try to argue. |
@aturley Yes, i think you are correct. |
Copying my comments from the original Zulip thread:
And one example that more closely matches the https://playground.ponylang.io/?gist=4fe7e1b7403332e25a997ad29e482ea7 |
Copying zulip conversation context:
|
I agree with the statements above from @EpicEric - the lambda should be given the elements to compare. Coming up with an object -> integer mapping is not always feasible for the things I may want to sort. Apart from the specific concerns that @EpicEric mentioned above, I want to add more concerns into the mix: Imagine I have an object that I want to sort based on comparing multiple fields. In order to convert them to a Further, this approach of converting all fields of the object into a numeric representation and squeezing them into a To use a real world example from code I have written, consider a
There are 96 bits of information to consider for sorting purposes, and I'll never be able to fit all of those bits into a |
@damon-kwok what "real world" code can you point to that is using this SortBy? I think knowing that could help pinpoint additional tests, usage patterns that should be experimented with before this would be considered for the standard library. |
@jemc If you have an extreme case that Usize cannot represent, that's not what SortBy is dealing with. SortBy focuses on conditional evaluations rather than solving all problems.
|
@SeanTAllen Many real world cases: Leveldb manager:
A blog system,
A set of JSON data representing the product informationsort by storage date |
Focusing on existing types without compareable implementations. |
But that's not what I want to do. Maybe someone should add a new RFC for it. |
I named it SortBy rather than any other name, hoping that it would be as simple and elegant as possible, and that no new types should be added for sorting. Otherwise it should be called something else. |
With a generic lambda approach like the one I showed above, adding a primitive SortBy[A: Seq[B] ref, B: Any #read]
fun apply(seq: A, f: {(B): USize} val): A^ =>
Sort[A, B, SortFunction[B]](
seq,
object val is SortFunction[B]
fun lt(first: B, second: B): Bool => f(first) < f(second)
fun le(first: B, second: B): Bool => f(first) <= f(second)
fun gt(first: B, second: B): Bool => f(first) > f(second)
fun ge(first: B, second: B): Bool => f(first) >= f(second)
end)
actor Main
new create(env:Env) =>
let array = [ "aa"; "aaa"; "a" ]
SortBy[Array[String], String](array, {(x: String): USize => x.size() })
for e in array.values() do
env.out.print(e) // prints "a \n aa \n aaa"
end https://playground.ponylang.io/?gist=144512d4a8417b60452e3084b4c3f32d As a side note: due to the need for a concrete type, you can't avoid adding the |
@EpicEric I have a few questions:
|
@EpicEric Can you create a temp git repository and submit a |
It doesn't. You'd create a sort function using the primitive TimeSortFunction is SortFunction[Time]
fun lt(first: Time, second: Time): Bool =>
(first.total_seconds < second.total_seconds) || (
(first.total_seconds == second.total_seconds)
&& (first.nanosecond < second.nanosecond))
fun gt(first: Time, second: Time): Bool =>
(first.total_seconds > second.total_seconds) || (
(first.total_seconds == second.total_seconds)
&& first.nanosecond > second.nanosecond))
fun le(first: Time, second: Time): Bool =>
(first.total_seconds < second.total_seconds) || (
(first.total_seconds == second.total_seconds)
&& first.nanosecond <= second.nanosecond))
fun ge(first: Time, second: Time): Bool =>
(first.total_seconds > second.total_seconds) || (
(first.total_seconds == second.total_seconds)
&& (first.nanosecond >= second.nanosecond))
primitive TimeSort[A: Seq[Time] ref]
fun apply(a: A): A^ =>
Sort[A, Time, TimeSortFunction](a, TimeSort)
This RFC doesn't have any code implementation, so I'm assuming you refer to this code. In this case, yes, there is one extra anonymous object allocation.
This is only if API names have to follow the same convention as the rest of the |
@EpicEric Thanks! I see. I know the process of adding RFC is long and we can listen to other people's ideas. |
Do you still want to add this RFC? While this may be a reasonable addition, I feel that it violates least surprise as it exists. Specifically:
It does not appear to me that a comparison-based solution has a very significant difference in allocation. If it just requires a single method (such as compare), then the allocation characteristics will be identical to a lambda returning USize. Of course as with HashFunctions we can have a generic primitive to dispatch without allocation in the general case |
@jasoncarr0 Do you mean to change |
I would actually expect |
@jasoncarr0 Updated. |
I agree with the commenters that I would expect something called Here's a survey of languages sorting support
|
This PR adds my RFC for
SortBy
primitive.