lintr
lintr copied to clipboard
implicit_integer_linter shouldn't lint 1:10 (optionally?)
lintr::lint("1:10\n", lintr::implicit_integer_linter())
# <text>:1:2: style: Integers should not be implicit. Use the form 1L for integers or 1.0 for doubles.
# 1:10
# ~^
# <text>:1:5: style: Integers should not be implicit. Use the form 1L for integers or 1.0 for doubles.
# 1:10
# ~~^
but typeof(1:10)
is "integer"
, and the performance is essentially identical:
microbenchmark::microbenchmark(
1L:10L,
1L:10,
1:10L,
1:10,
times = 1e6
)
# Unit: nanoseconds
# expr min lq mean median uq max neval
# 1L:10L 199 242 479.8983 257 284 89303201 1e+06
# 1L:10 197 237 376.0418 251 278 10444161 1e+06
# 1:10L 198 239 354.6013 252 280 10678523 1e+06
# 1:10 190 233 405.9966 246 274 14666175 1e+06
implicit_integer_linter isn't really about performance, more about explicit typing.
right -- the more important point is that identical(1:10, 1L:10L)
. the performance bit is just demonstrating that there's no performance reason to prefer one or the other either.
Is there a philosophical difference to identical(1.0, 1)
?
to me, it's different -- almost everywhere in R, 1
actually means 1(double)
(according to the parser). but with 1:10
it's actually 1(integer)
(in effect, i.e., at runtime).
for 1.0
v 1
, as I understand it we only like 1.0
as a way of signalling "yes, this is a double, it doesn't need to be 1L
" to the linter.
put another way -- the linter wants 1
to be 1L
whenever possible. it aims to set the default numeric literal to integer, and only allow doubles with decimal points. but for 1:10
, 1
is already (in effect) integral, so there's no need to intervene.
that's how I see it at least.
PS I used to be a stickler about writing 1L:10L but got sick of the extra characters and especially at the cost of typing difficulty -- typing 1L:10L
requires some deft coordination to get the shift key pressed in exactly the right places
I tend to rarely need the :
with literals, usually seq_*()
functions provide a nicer solution.
To me the improved clarity of intent is worth the extra effort spent typing.
:
is super odd anyway, compare 1.0:3.5
with 1.5:3
for example.
are you OK with adding an option to disable for :
(it can be off by default)
Yes, that'd be okay. What about other such cases, e.g. seq_len(42)
and seq.int()
?
personally I use L
equivalents for those cases. i don't have any justification for the difference :)
Okay, so the argument could be named allow_colon = FALSE
And what about, say, list1[[1]]
?
Revisiting this...
Here in the source, the arguments to a:b
are explicitly converted with asReal()
:
https://github.com/r-devel/r-svn/blob/f941f28d2db0f3ecbe4ae355a6b39d4f5612e592/src/main/seq.c#L166-L167
So 1:10
is consistent with what the code is actually doing / doesn't require casting.
And what about, say,
list1[[1]]
?
Maelle, I think that's one of the more common places where I think of this linter as "good", I definitely think it should lint. My thinking is leaving this linter off is the better option if you don't think it should lint...
Please open a separate issue if you'd like to discuss more, this one will close with #1691