Comments (8)
The problem is that pipeR has different rules of piping. Please note that your original code without piping is
qplot(mpg, wt, data = mtcars)
In this code, you don't actually pipe mtcars
to the first-argument of qplot()
.
%>>%
implements a set of rules to determine where the object should be piped to.
The rules are best described by the following demos:
x %>>% f # f(x)
x %>>% f(...) # f(x,...)
x %>>% { f(.) } # f(x)
x %>>% ( f(.) ) # f(x)
x %>>% (i -> f(i)) # f(x)
x %>>% (i ~ f(i)) # f(x)
You need to be aware that if you supply a function name or call, the object will be piped to its first argument. If it is not what you want, you can enclose your function call or expression with ()
or {}
so that .
represents the piped object.
Therefore, the right code should be
mtcars %>>% ( qplot(mpg, wt, data = .) )
magrittr's %>%
analyzes your expression heuristically and detect .
symbols to determine whether it is first-argument piping or only piping to .
. I'm not sure if I like this kind of heuristic design because it can be sometimes ambiguous and unpredictable. I always believe that heuristic design is good for interactive analysis for saving a lot time, but may not be the best solution for programming because it may add extra unpredictability which is undesired for coding.
Suppose we define the following function f(x,y)
:
library(magrittr)
library(pipeR)
f <- function(x,y) {
cat("x = ", x, "\n")
cat("y = ", y, "\n")
}
Then we use magrittr to pipe:
> # only pipe to .
> 1:10 %>% f(.)
x = 1 2 3 4 5 6 7 8 9 10
Error in cat("y = ", y, "\n") : argument "y" is missing, with no default
>
> # pipe to first argument
> 1:10 %>% f(1)
x = 1 2 3 4 5 6 7 8 9 10
y = 1
>
> # only pipe to .
> 1:10 %>% f(.,.)
x = 1 2 3 4 5 6 7 8 9 10
y = 1 2 3 4 5 6 7 8 9 10
>
> # pipe to first argument and .
> 1:10 %>% f(length(.))
x = 1 2 3 4 5 6 7 8 9 10
y = 10
>
> # try to pipe to first-argument but does not work
> 1:10 %>% f(length(.),length(.))
Error in f(`1:10`, length(.), length(.)) : unused argument (length(.))
>
> # try to pipe to first-argument but does not work
> 1:10 %>% f(c(.,1),c(1,.))
Error in f(`1:10`, c(., 1), c(1, .)) : unused argument (c(1, .))
It looks like %>%
can be sometimes smart but I don't feel that I have power to control its behavior because if you are not fully aware of its heuristic rules to determine whether to pipe to first argument or just pipe to .
its behavior won't be so predictable.
That's why %>>%
is designed to behave based on a set of very intuitive rules so that when you write your code, you know what and how the object will be piped.
- If you want to pipe the object to the first argument, just give
%>>%
a function name or call. - If you want to pipe it to somewhere else (not the first argument), just enclose your expression by
{}
or()
. - If you want to name the symbol that represents the piped object yourself, just enclose your expression by
()
and give a lambda expression like(x ~ f(x))
.
That's how it works and you fully know what is going to happen.
from piper.
Another example may expose the problem more fully.
Consider the following function:
f <- function(x,y,z = "z") {
cat("x = ", x, "\n")
cat("y = ", y, "\n")
cat("z = ", z, "\n")
}
If I run the following code:
> 1:10 %>% f(.,2)
Do you have any confidence to guess what is going to happen? Will 1:10
be piped to the first argument as if f(1:10, 1:10, 2)
; or only pipe to .
as if f(1:10,2)
?
The answer is only pipe to .
:
> 1:10 %>% f(.,2)
x = 1 2 3 4 5 6 7 8 9 10
y = 2
z = hello
as if f(1:10,2)
.
But see what happens here:
> 1:10 %>% f(1,length(.))
x = 1 2 3 4 5 6 7 8 9 10
y = 1
z = 10
It pipes to the first argument as if f(1:10,1,length(1:10))
.
More examples:
> 1:10 %>% f(1,(.))
x = 1 2 3 4 5 6 7 8 9 10
y = 1
z = 1 2 3 4 5 6 7 8 9 10
> 1:10 %>% f(1,.)
x = 1
y = 1 2 3 4 5 6 7 8 9 10
z = hello
How confident and responsive are you if I give you more examples? Does it cost more efforts to read or write code and be sure what's going to happen?
What if you really want only pipe to .
as if f(mean(1:10),length(1:10))
? but
> 1:10 %>% f(mean(.),length(.))
x = 1 2 3 4 5 6 7 8 9 10
y = 5.5
z = 10
All the problems above does not exist in pipeR's %>>%
because you have the full control of how it works.
from piper.
Impressive! I have finally seen the fatal ambiguity of "magrittr" package and how "pipeR" solves it. I guess it would be better to add a little bit more in "Usage" section of "%>>%" to explain the difference of "x %>>% f(...)" and "x %>>% ( f(.) )", which should be an important key feature to clarify earlier.
from piper.
Yes, I would do something about it. Thanks. :)
from piper.
Fair enough to have an opinion; we'll keep it in mind.
I must admit i see this more as negative propaganda than constructive criticism. Maybe it's just your journalistic style.
from piper.
If too much ambiguous code is produced, it would be fatal disaster. Let people know such potential exists is exactly the constructive criticism.
from piper.
As a package user but not a package developer, I may be more neutral to have my opinion. I think @renkun-ken has pointed out a potential confusion and provided a solution in his package. It would be fine for him to keep such problem be hidden in "magrittr" package until last minute by not posting anything in "magrittr" issue list. Since it should not be hard for "magrittr" to find another solution, I do not think his posting is a negative propaganda as you said.
from piper.
Thanks @yanlinlin82. Let's keep cool and find what is best for the community.
from piper.
Related Issues (20)
- Handling incorrect usage of `.` (dot) HOT 17
- Support I() to avoid symbol clash HOT 1
- Does not support piping with lhs value unevaluated
- Consider class-based implementation of Pipe object HOT 1
- Preserve the visibility of output HOT 1
- Pipe's error HOT 2
- package?pipeR problem HOT 2
- Support operator-free pipeline HOT 2
- cat() string in pipeline HOT 1
- Add support of question mark as binary operator HOT 5
- Consider supporting question mark as ternary operator HOT 1
- Support global assignment
- not compatible with assign function HOT 6
- Pipe() HOT 2
- Have you thought of creating a pipeR version %<>>% of magrittr %<>%? HOT 2
- Leaked variable HOT 1
- Interfacing with data.tree
- use apply()
- debug(%>>%) for a pipe
- mouse support
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from piper.