-
Notifications
You must be signed in to change notification settings - Fork 188
Create all_equal_linter() #2885
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
base: main
Are you sure you want to change the base?
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2885 +/- ##
=======================================
Coverage 99.27% 99.27%
=======================================
Files 128 129 +1
Lines 7160 7177 +17
=======================================
+ Hits 7108 7125 +17
Misses 52 52 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
a7111d8
to
a5e900b
Compare
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.
Shall we cover attr.all.equal
too?
Either TRUE (NULL for attr.all.equal) or a vector of mode "character" describing the differences between target and current.
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.
I would say probably not. Since it returns NULL
in the case of no differences, I would expect that it's already wrapped in is.null()
and thus safe.
#' Usage of `all.equal()` without wrapping it is `isTRUE()` in `if` clauses, or | ||
#' preceded by the negation operator `!`, are thus likely to generate unexpected | ||
#' errors if the compared objects have differences. | ||
#' An alternative is to use `identical()` to compare vector of strings or when |
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.
I wouldn't advertise this:
isTRUE()
is specifically designed to overcome shortcomings ofidentical(x, TRUE)
- I guess it's rare to do something like
identical(all.equal(x, y), "Mean relative difference ...")
There may be some advantages to identical()
but I don't think we need to cite them here, too detailed
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.
I think it became clearer later in the review but the idea was not to recommend wrapping all.equal()
in identical()
. I agree isTRUE()
is a better solution here.
But I have seen the following thought process happen:
x <- letters
if (x == letters) {
message("success")
}
#> Error in if (x == letters) {: the condition has length > 1
# Oh no, it doesn't work. How can I compare that all elements of x are equal to
# elements of letters
if (all.equal(x, letters)) {
message("success")
}
#> success
Created on 2025-07-23 with reprex v2.1.1
In reality, in these cases, the author was really looking for identical()
, not all.equal()
.
I have the feeling this is what happened in most cases where all.equal()
compares character vectors (see https://github.com/search?q=org%3Acran%20%2Fall%5C.equal%5C(names%5C(%2F&type=code). This might be a good new case for this linter in a follow up PR.
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.
Would you have a suggestion to phrase this idea more clearly?
#' ) | ||
#' | ||
#' lint( | ||
#' text = '!identical(a, b)', |
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.
I would just use isTRUE()
, I think that's the safest drop-in alternative
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.
I see, this corresponds to the clarified note in the lint_message
... maybe just add a comment above this example with the same clarification about not needing tolerance?
#' preceded by the negation operator `!`, are thus likely to generate unexpected | ||
#' errors if the compared objects have differences. | ||
#' An alternative is to use `identical()` to compare vector of strings or when | ||
#' exact equality is expected. |
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.
BTW stopifnot()
has some built-in logic for handling all.equal()
checks, c.f.
stopifnot(all.equal(1, 1.001))
# Error: 1 and 1.001 are not equal:
# Mean relative difference: 0.001
I might actually lint this code while we're at it:
stopifnot(isTRUE(all.equal(x, y)))
Since it gives a worse error:
stopifnot(isTRUE(all.equal(1, 1.001)))
# Error: isTRUE(all.equal(1, 1.001)) is not TRUE
Some hits:
We can do that as a follow-up if you'd like; in this PR at least I'd want to have some mention of stopifnot()
.
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.
We might as well test isFALSE(all.equal())
here too, it gets some usage:
https://github.com/search?q=lang%3AR+%2FisFALSE%5C%28all%5C.equal%5C%28%2F&type=code
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.
Yes, isFALSE(all.equal())
is definitely wrong since it'll always return FALSE
. I wonder if that'd fit better under a istrue_linter()
that check cases where authors wanted !isTRUE()
rather than isFALSE()
.
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.
Similarly for stopifnot()
, great catch but I wonder if it should live here or in stopifnot_all_linter()
🤔
]" | ||
) | ||
|
||
xml_nodes_to_lints( |
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.
If we don't end up covering more cases in this linter, that'd be a good candidate for make_lint_from_function_xpath()
.
Fix #2610