answer <- sales |> keep(region == "West") |> take(2)
class(answer)[1] "god_pipeline"
A verb does not return a table. It returns a pipeline, which is a plan for one.
answer <- sales |> keep(region == "West") |> take(2)
class(answer)[1] "god_pipeline"
answer = sales >> keep(col.region == "West") >> take(2)
type(answer).__name__'Pipeline'
Printing it runs it, which is why the examples so far have shown tables rather than plans. When you want the table itself, ask for it with collect.
nrow(collect(answer))[1] 2
len(collect(answer))2
The plan buys you speed. Steps cost nothing until you ask, and then the whole sentence reaches the engine as one query. Six steps are not six passes over the table, because the engine sees the whole question first. The machine underneath shows a pipeline arriving whole.
In R this matters for more than speed. sort and keep are names other packages use too, so a pipeline can reach some other package’s sort by mistake. A pipeline is not a table, so that sort has no meaning for it, and the call stops rather than returning a plausible answer from the wrong tool.
Forgetting collect is covered by the same protection. Ask a plan a table’s question and R’s own answers would be quietly wrong. names(answer) would list the plan’s own parts, and nrow(answer) and answer$revenue would be NULL. NULL flows onward: sum(answer$revenue) would be 0, with no complaint anywhere. So a pipeline refuses the question and names the repair:
answer$revenueError:
! a pipeline is a plan for a table, and `$revenue` asks the plan for a column. Nothing has run yet: `collect(pipeline)$revenue` asks the table it makes
Python needs no guard built for this. A pipeline there has no length, no brackets and no iteration, so the same mistake stops itself, with the language’s own error.
You can also see what the verbs wrote, which is the text form, and it is the same sentence in both languages.
cat(format(sales |> keep(region == "West") |> take(10)))sales
then keep where ([region] is "West")
then take 10
print((sales >> keep(col.region == "West") >> take(10)).written())sales
then keep where ([region] is "West")
then take 10
The two calls answer with the same bytes, and only their names differ. format is the word R already owns for turning a thing into text. Python’s format means something else, so its method says what it gives. What comes back is the text form: the sentence with no pipe glyph and neither language’s column spelling left, which is what the next chapter stores, sends and runs.
Printing is also how a notebook shows a pipeline. In Jupyter, and on every page of this book, a pipeline standing at the end of a cell renders as a real table rather than as monospaced text. Each binding tells its notebook how to display one, so the answer is the same everywhere and only the rendering differs.
The whole rule is one sentence. Display runs a pipeline for free; anything else asks with collect.