PipelessPipes.jl is not a package, yet, as I would be interested in hearing some opinions first. Here are my thoughts about Pipe.jl and Lazy.jl, which I have tried previously:
- _ syntax is nice and non-magic
- I don’t like typing
- The last entry of a pipe can’t have a trailing
|>, making it harder to comment out parts
- If there’s an error in one part, the whole expression errors and VSCode can’t highlight the specific part
- end of pipeline just “dangles” in terms of indentation, which means the IDE always tries to indent also the following lines
- you can’t really interject some random statement for checking what’s going on inside the pipe that well
- begin / end is nice for indentation after
- Not every function needs piped thing as first argument, like
filter(also not necessarily last, the other option
- Looks a bit too magic for me when the first argument is not visible at all
edit: As I’ve made some changes since the first post, and have registered those changes now, here’s the relevant excerpt from the readme
PipelessPipes defines the
@_ macro. It takes a start value and a
begin ... end block of expressions.
The result of each expression is fed into the next one using one of two rules:
- There is at least one underscore in the expression
_is replaced with the result of the previous expression
- There is no underscore
- the result of the previous expression is used as the first argument in the current expression, as long as it is a function call or a symbol representing a function.
Lines that are prefaced with
@! are executed, but their result is not fed into the next pipeline step.
This is very useful to inspect pipeline state during debugging, for example.
Example with a DataFrame:
using DataFrames, PipelessPipes df = DataFrame(group = [1, 2, 1, 2], weight = [1, 3, 5, 7]) result = @_ df begin filter(r -> r.weight < 6, _) groupby(:group) @! println("There are $(length(_)) groups after step 2.") combine(:weight => sum => :total_weight) end
The pipeless block is equivalent to this:
result = let var1 = filter(r -> r.weight < 6, df) var2 = groupby(var1, :group) println("There are $(length(var2)) groups after step 2.") var3 = combine(var2, :weight => sum => :total_weight) end
For debugging, it’s often useful to look at values in the middle of a pipeline.
You can use the
@! macro to mark expressions that should not pass on their result.
For these expressions there is no implicit first argument spliced in if there is no
_, because that would be impractical for most purposes.
For the error message point, look at the difference to
Pipe.jl here from some random code of mine:
I wonder what the best name for the macro is, because all the good ones are already taken by other packages. I like
@_ because it’s really short, although it would conflict with Underscores.jl, if one wanted to use both.
The other question is if this ruleset has some obvious problems to you. I haven’t found serious issues so far, but maybe I’ve overlooked some circumstances under which this expression parsing would break.