magrittr icon indicating copy to clipboard operation
magrittr copied to clipboard

Use () after all function calls

Open krlmlr opened this issue 5 years ago • 7 comments

in README.

krlmlr avatar Nov 15 '20 12:11 krlmlr

Stefan prefers without parentheses.

lionel- avatar Nov 16 '20 09:11 lionel-

Stefan prefers without parentheses.

Yeah, IMO that's way cleaner and less typing. Also, I think more of RHS as functions/expressions, so like in that one does not write lapply(foo, bar()). I know the analogy does not fully extend to the situation with other args, but still I prefer thinking of RHS as not being a function call standing on its own... I like the cleanliness and the interpretation that comes with no parens.. but that's just my opinion.

smbache avatar Nov 16 '20 10:11 smbache

Thanks. A few thoughts:

  • Typing speed is often less relevant than reading speed, in particular for production code that is ever read after being written (e.g., any script not named "Untitled[0-9]*").
  • Always adding parentheses is consistent -- there is no difference between 1 and > 1 arguments. IMO this wins over perceived cleanliness.
  • The tidyverse style guide explicitly demands parentheses in this case.
  • I do not think of the f(...) in x %>% f(...) as a function call, with or without arguments. It could be interpreted as a special form of currying. I don't think it should be necessary to understand currying in order to understand the pipe.
  • Avoiding the special case of unary function simplifies the documentation.

How about a new section about omitting the parentheses for unary functions?

krlmlr avatar Nov 16 '20 11:11 krlmlr

Well the style guide is obviously not a very stylish guide in this case ;-) as I said, my opinion is not the only one, and I don't have to make all decisions. I don't see omission of () any less consistent than omission of parens in arithmetic when they're not necessary and when precedence is clear.

smbache avatar Nov 16 '20 20:11 smbache

#236 is another reason to teach users the longer form first:

library(magrittr)
mtcars$cyl %>%
  forcats::as_factor
#> Error in .::forcats: unused argument (as_factor)

Created on 2020-12-05 by the reprex package (v0.3.0)

What's a good way to move forward?

krlmlr avatar Dec 05 '20 22:12 krlmlr

Hi all, For teaching purposes, I'm trying to find any information or history on why/how %>% allows for function names without parenthesis on the RHS (for single argument uses). I tried to figure out if internally the pipe is using match.fun or something else but I am still unsure. I think this is relevant, given that the new base pipe does not allow functions on the RHS without parenthesis even when the only argument is whatever is being piped into them.

Thanks!

luisDVA avatar Jan 18 '22 01:01 luisDVA

FWIW, not including a function call produces a lint:

library(lintr)

# will produce lints
lint(
  text = "1:3 %>% mean %>% as.character",
  linters = pipe_call_linter()
)
#> <text>:1:9: warning: [pipe_call_linter] Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.
#> 1:3 %>% mean %>% as.character
#>         ^~~~
#> <text>:1:18: warning: [pipe_call_linter] Use explicit calls in magrittr pipes, i.e., `a %>% foo` should be `a %>% foo()`.
#> 1:3 %>% mean %>% as.character
#>                  ^~~~~~~~~~~~

# okay
lint(
  text = "1:3 %>% mean() %>% as.character()",
  linters = pipe_call_linter()
)

Created on 2022-10-11 with reprex v2.0.2

Additionally, native pipe requires a function call:

library(lintr)
lint(
  text = "1:3 |> mean |> as.character",
  linters = pipe_call_linter()
)
#> <text>:1:1: error: [error] The pipe operator requires a function call as RHS
#> 
#> ^

Created on 2022-10-11 with reprex v2.0.2

For these reasons, I agree with Kirill here that the README should include function calls.

IndrajeetPatil avatar Oct 11 '22 07:10 IndrajeetPatil