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
change propEq/pathEq parameters order #2938
change propEq/pathEq parameters order #2938
Conversation
540cbe6
to
b9e04c8
Compare
Thank you very much. I think this is a very positive change, but I'd like to leave it open for a bit to hear back from others. Any objections, @ramda/core? |
This is a big breaking change. I think it's good but I think it's not fair to make this without bumping to 1.0. |
@CrossEye What do you think about using this one as an impetus to get to 1.0? It's a positive change, and we can look at the other path stuff, clean it up, then clear this out and 💥 |
@Bradcomp: That sounds like a very good idea. |
Any news on this? I just spent 15 minutes debugging why this didn't work: R.propSatisfies("name", R.test(queryRegex)) |
This is one of the few open issues that I think might be worth a breaking change in |
My personal preference would be to stop releasing breaking changes in minor v0 releases especially if we're committed to release v1.0 as soon as possible. As much as I prefer having a non-breaking v1.0, I think these changes bring some consistency and v1.0 is probably the best time to introduce such breaking change. I'm in favour of this change but would prefer to release it as part of v1.0 |
4affc53
to
5c1855f
Compare
5c1855f
to
3b76eb1
Compare
@adispring I took the liberty to update your branch:
@CrossEye I think this change was welcomed by pretty much everybody in the team. Could we merge this now and ship it in v1.0? I already added that milestone :) |
Is it more natural to keep current |
I think your change makes more sense as it focus on the value first as opposed to where the value is: var isJohn = propEq('john');
isJohn('name', {name: 'john'});
isJohn('first_name', {first_name: 'john'}); With the current parameters order you would have to flip the function first. |
OK. |
@customcommander wrote
How to order the arguments is not so clear cut as your comment suggests. Is not
the principle of Ramda? With that principle, the "focus" should sharpen with the position of the argument – so the most general would be first. In the test example What the least-changing or most general is, may depend on the particular context. E.g. I use more often the flipped version of If this change comes through, we may eliminate the inconsistency with |
I don't think this is necessarily going against the philosophy of putting data last. We simply have different opinions about what the least-changing parameters are. For me You make reasonable observations (as always) but we don't need to put everything into the same bag either. I don't see This PR has been opened for more than two years now so we ought to make a decision at some point. Do you feel strongly against this change? |
No, I have anticipated (feared) this breaking change might come eventually and moved away from I was just asking if someone else had a consistent conception about the order of parameters in Object-accepting functions of Ramda. This PR might be the right place to ask I thought. |
I don't think there is any universal answer to these questions. For the majority of Ramda functions the order feels immediate, and obviously correct. But some, like |
@whitelizard Thanks for working out the concept of naming functions. It is easy to remember and brings consistency to the vast API surface. Your Steps 1 and 2 should
I also agree that naming I briefly checked the list of Ramda functions, if they comply with your Steps 1 and 2. I came up with just a few mismatches!
(last updated 21 July 2023) |
This was quite the unexpected breaking change for a minor version. While I understand the benefit, unlike with removed or renamed functions the change from e.g. It would be fun if people would comment here the amount of time they spent tracking the bug before finding the culprit and the amount of time they spent refactoring their codebases. :) |
i spend 3 hours to find this change in my test case today morning, and will spend 4 hours afternoon to refactor my code. 😭 |
@yuercl Don't forget that A full text search 'n replace over all my code seems inevitable. That's why, I am staying on v0.28 where I can. |
@crshmk Is there a workaround for this? |
@Lambdaphile to recreate the import { __, propEq } from 'ramda'
const idEq = propEq(__, 'id') If you have a lot of broken "dependencies": {
"ramda": "=0.28.0"
} However, if you use ramda in many different apps, managing two different incompatible versions across them is unwieldy at best and impossible if they share code. This is actually the larger issue. To use // propEq.js, kept in local utils
import { curry, equals, prop } from 'ramda'
export const propEq = curry((name, val, obj) =>
equals(val, prop(name, obj))) // app.js
import { filter } from 'ramda'
import { propEq } from './utils' I have my own everyday ramda utils I've built over the years, so I just added it to those. In this way, all my apps can use version Finally, respectfully, the best solution would be to admit that we already litigated this and to revert, preferably quickly. |
It was not a good idea to reverse parameters of that function IMO =( because :
Sometime it's better to simply rename a function instead of changing its signature (I spent 2h to find the origin of bugs in my app) |
I got bit by this. While I agree with this change, these kinds of subtle breaking changes is what will prevent large adoption of this library. I wish this project to immediately release 1.0 and follow strict semver. Breaking changes are fine. Just make a new major release. That is what that is for! |
I agree. Every lib should actually always start with v1.0.0, from the very beginning, for the npm semver system to work well. I recommend to read e.g. this article on this subject: https://medium.com/javascript-scene/software-versions-are-broken-3d2dc0da0783 |
First, as a reminder for everyone, per the rules of semver, for major version zero, minor bumps should be considered breaking. Ref: https://semver.org/#spec-item-4 That being said, IMHO To address the argument order of
I'm going to argue that this consistency is the most important part here. What the argument order should be is completely subjective. As for function naming, we have a pretty decent convention going already, for the aforementioned functions, the convention is
If we fully qualify the names, we get this:
And the convention for these are To summarize, when prop/path comes first in the function name, prop/path is the second argument, and when prop/path comes second in the function name, prop/path is the first argument Now, that convention could also apply to the fact that prop/path second is "mutate" and prop/path first is "evaluate against". We could keep that naming convention for that purpose and have them all share the same general signature of In the end, I think consistency is the most important part here. Therefore I vote not to revert this MR. If it is decided that the argument order should be changed, then I would propose that, as part of a long overdue |
Every function should stand on its own and not be dependent on or ruled by other functions and their most logical & convenient names and signatures (arg order). I don't think that arg order is always subjective, but the name should reflect the order, that is most important. |
Good APIs have consistent and predictable behavior. And that includes function signatures and argument order. My point is that they should be consistent. I'm not particular about which of the 2 orders here is correct,
What I mean to say is the reasoning behind why the arguments should be in the order they are is subjective. Using your own example here
and
Let's rewrite these 2 signatures generically.
The idea that a "function" is further away from "data" than "value", so Besides, Whatever the order is, just have it be consistent. I don't disagree with you that |
For any future argument changes, I think the community would benefit greatly from codemods that |
@Harris-Miller I feel that you don't get my point. The naming is wrong, not the signature. As I wrote earlier: e.g. "valueAtProp" would be the better name if the prop name (key) comes first in the argument list ( It is not the start of the function name that refers to the first argument, it is the last part of the function name that should refer to the first function argument. This is because of currying. const ageIs = R.valueAtProp('age');
const isPerson20yearsOld = ageIs(20);
const celebratePerson = isPerson20yearsOld(person); Do you agree that the intention of ramda functions is to be able to use currying in the way like above? And that the names should read well with the argument that follows, like above? If the rules that I wrote in my first long post is followed, then the API would be entirely consistent. |
@whitelizard Yes I do agree. My arguments for why My goal is for consistency in behavior and expectation in the API.
Also agree, as it aligns with my stated goal |
So, the solution could be simple.
Release 1.0.0. Again, the order of designing any API function should be: Need -> Signature -> Name Never change the signature of a function to match the faulty name it unfortunately got. The signature was designed out of greatest utility. The name should change if it got a bad one. Changing the name is not initially a breaking change, it could start with a minor release of adding the new name to the API and flagging the old as "will be removed in the next major". Ramda could have this as part of its change strategy. |
100% agree with @whitelizard I also agree with having consistent functions in a library is a good thing, but maybe it would be a good thing also to add another function (temporary or not) to replace with when migrating. |
@whitelizard just to be clear, to extend on this table
While obviously incomplete, the table just represents the idea of deprecating existing fn columns, adding their replacements in the consistent name column, as well as adding new functions that don't currently exist For the sake of typescript I personally like having complementary functions CC: @kedashoe |
Yes, and I would extend that to a few binary functions too. They have crept up in Ramda-adjunct eg. This is always when "…the reasoning behind why the arguments should be in the order they are is subjective". Another example which comes to my mind is On the other hand, while you @Harris-Miller mention it, |
I know this has been beat to death, but I'd just like to add my two cents. I really hate this change. I just propEq and pathEq way more than propSatisfies. Plus, the naming, as other has suggested, practically tells you how to use it: prop, then equals. I've always had to look up the docs when needing propSatisfies simply because of the naming inconsistency. But even still, I think it would have made more sense to change propSatisfies to match the other two. /shrug |
would it be possible to mention this change in the thanks. |
Ouch. It seems pretty onerous have to change any and all calls to propEq/pathEq for such a flimsy and subjective reason. I get that the library will probably not change back to its historical API at this point, but this seems hostile to longtime users, and it certainly makes me consider the wisdom of moving away from a dependency on Ramda. |
Make
propEq/pathEq
parameters order be consistent topropSatisfies/pathSatisfies
parameters order.related to #2937