-
Notifications
You must be signed in to change notification settings - Fork 186
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
(WIP) Allows the use of = instead of <- #2521
base: main
Are you sure you want to change the base?
Conversation
63f122f
to
e547608
Compare
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2521 +/- ##
==========================================
- Coverage 97.96% 97.95% -0.02%
==========================================
Files 126 126
Lines 5760 5770 +10
==========================================
+ Hits 5643 5652 +9
- Misses 117 118 +1
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. |
Thanks for filing! WDYT about two new arguments instead:
That enables the full generality of use cases here I believe, e.g.
Or, we can do similar to lintr/R/pipe_consistency_linter.R Line 35 in 901d9ed
E.g. |
Another major wrinkle about a = 1
b <- 2
if (any(idx <- x > 0)) foo()
|
Thank you for taking time to review this.
But is there a user case? Aside from people who just like to spread chaos. In any case, if we want to allow something like that, I would go for your second solution.
I will make the assumption that the most common operation will be switching from Just modifying the logic will be quite a bit more complicated (compared to the current change) and I will need to learn how to write linter. So this will take some time.
That's a feature of |
R/assignment_linter.R
Outdated
@@ -88,7 +91,7 @@ assignment_linter <- function(allow_cascading_assign = TRUE, | |||
|
|||
xpath <- paste(collapse = " | ", c( | |||
# always block = (NB: the parser differentiates EQ_ASSIGN, EQ_SUB, and EQ_FORMALS) | |||
"//EQ_ASSIGN", | |||
if (allow_equal_assign) "//LEFT_ASSIGN" else "//EQ_ASSIGN", |
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.
Won't this also lint data.table code if allow_equal_assign
is True? e.g. dt[, x := 42L]
.
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.
That's a great catch that made me understand what [text() = '...']
does. The latest commit should fix it. I included a test as well.
I'm not sure, I think it's a matter of opinion. So we could support both approaches. A really cursory GitHub search suggests this approach to inline assignment is very rare, e.g. 50x less common than assigning inline with I'm happy to defer to that to follow-up work we can take on if you're not keen. Either way I'd like this to simmer a while before CRAN release, so I'd defer merging this until after "ongoing" CRAN release. |
Interesting. If you ask me, I would consider inline I am happy with this as long as there is a toggle for it.
I am more than happy to do so, and in no rush to get it on CRAN ASAP. Let's get the desired behaviour and implementation right. In fact, I am pleasantly surprised by the attitude to allow parametrization of lints to allow any desired style, since it brings hope that I could implement rules for by banner-style indentation. Since the behaviours we want now are getting quite complex, I will first implement tests according to desired behaviour and then tweak the code. Let me reiterate. We have |
I think in practice calling if ({
x = 2
} > 2) { ... } i.e., on the AST it looks exactly like any other
Perfect. IMO there are four styles we should accommodate for now. Any further customization will have to come with future FRs.
Maybe that fits under cc @AshesITR / @IndrajeetPatil on design here.
Feel free to file an issue! Most likely, you'll need to implement it yourself, but I can't see why we wouldn't accept such a PR. |
Another case against inline assignments using braces is Maybe what we want is to block |
Sorry, but I don't understand this point. What is the expected and what is the desired behaviour of |
There are dozens of us, dozens!
I am not sure I understand the difference between "required" and "always".
And as @AshesITR suggested, splitting it into two switches, one for |
compare local(x <- 42) and local({x = 42}) |
I am comparing and comparing and they produce identical results. a = local(x <- 42)
exists("x") # false
b = local({x = 42})
exists("x") # false
a == b # TRUE For a moment I was afraid that |
Oh, that's somewhat surprising to me as well! Thanks for double-checking. OTOH, that could be specific to |
I'm also surprised by the discovery. I see two options: 1. not treat "inline" differently or 2. make up some best-effort definition and use that. For 2. we could for example declare all assignments inline unless they are top-level, top-level within a function body or control statement body, or top-level within a multi-line brace expr. Examples: a <- 1 # top-level
function(x) { c <- x } # top-level within function
local({ e <- 2 }) # inline
local({
f <- 1 # top-level within multi-line brace expr
})
g(h <- 1) # inline
if (i <- 1) {} # inline
if (TRUE) { i <- 1 } # top-level within control statement body
if (TRUE) i <- 1 # top-level within control statement body |
implicit_assignment_linter() has a lot of logic to do so already |
Since you are a co-author on that one, do you think that the logic would work for Link so its easier: https://github.com/r-lib/lintr/blob/HEAD/R/implicit_assignment_linter.R I see that if we go from the simple: Assignment is either Perhaps, if But otherwise, we are essentially including the functionality of Is it even worth it? Wouldn't |
We've merged linters in the past already where it made sense, so code duplication shouldn't be a huge concern. |
dc3ab81
to
a4fb906
Compare
Rebased to latest main. Converted to draft. |
With life finally getting out of the way, I am back working on this. Rereading the whole discussion after some time off, I think the most important part is here (aside of implicit
With less words:
This looks like we have explicit So if we handle the explicit case only and leave Something like The only issue would be writing the XPath statement to not touch implicit |
Hello just wanted to comment -- good work all! I have been trying to incorporate Discussion for those interested as well as a competing style guide (MLR3 style guide) that contradicts |
New behaviour not yet implemented
…nto equal_assignment_lintr
Finally coming back here myself. @J-Moravec OK yes, I agree about implicit assignments being a bit of a distraction for the main feature here (top-level assignment style). I think we should focus on getting a good rule in place for top-level assignments, and then move on to fine-tuning the rules in further follow-ups later. For the implementation, I would start by writing good test cases. Usually I find the proper XPath falls out from there. Once you have test cases written, push them to this branch and if you're still stuck, please ping me and I'll pitch in. Thank you! |
@MichaelChirico Yeah, the complexity started to increase when I tried to consider implicit assignments as well. Sadly, my free time has disappeared since my baby grew into a toddler and the little guy likes to go sleep at 10pm. |
that sounds all too familiar 😭 |
This is a tiny change that solves #2441.
By adding
allow_equal_assignment
parameter to theassignment_linter
which defaults toFALSE
, we give an option to use=
instead of<-
.Associated tests are passing. Some other non-associated tests are failing though. But that seems unrelated.
Potential improvements:
equality
instead ofequal
? The latter might be already in use.xpath
nottrailing_assign_xpath
. Since the linter assumes<-
instead of=
by default, thetrailing_assign_xpath
might warrant changes as well. But this goes above my current knowledge of how linters actually work.Review is warranted.
Thanks.
edit: Fixed issues highlighted by github actions (didn't run
document()
andlintr
and force-pushed.For some reason,
test-lint_dir
fails for me, but doesn't file on github actions:and
lintr::lint_package()
complained about not being able to read the.lintr
config, but it somehow works now so I have no idea why it failed in the first place.