# A simple macro to transform \`newcol = fn(:col)\` to \`:col =\> fn =\> :newcol\`; friendly with DataFrames.jl

**URL:** https://discourse.julialang.org/t/a-simple-macro-to-transform-newcol-fn-col-to-col-fn-newcol-friendly-with-dataframes-jl/45893
**Category:** New to Julia
**Created:** [September 1, 2020, 1:14pm UTC](https://discourse.julialang.org/t/a-simple-macro-to-transform-newcol-fn-col-to-col-fn-newcol-friendly-with-dataframes-jl/45893 "2020-09-01T13:14:19Z")
**Posts on this page:** 2
**Page:** 1

<div class="post-metadata">

### Author: ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)
#### Post date: [September 1, 2020, 1:14pm UTC](https://discourse.julialang.org/t/a-simple-macro-to-transform-newcol-fn-col-to-col-fn-newcol-friendly-with-dataframes-jl/45893/1 "2020-09-01T13:14:19Z")

</div>

In DataFrames.jl there are a number of places where you have use this syntax `:col => fn => :newcol` to compute new columns. This makes sense once you get used to it, but sometimes you want a traditional syntax of `newcol = functionName(:col)`

So I decided to learn a bit of metaprogramming and try my hands at writing a simple macro. I think DataFramesMeta.jl does so some transformations like this but more complete. I hope that I can contribute to that in the future.

I call the macro **P** air **A** s **P** ipe so `@pap`.

Coding tips for macros more than welcome.

**Usage**

```julia
df = DataFrame(X = 1:3)
replacex(x) = x .* 2

# macro-less DataFrames.jl way
transform(df, :X => replacex => :newX)

# pap way with named new col
transform(df, @pap newX = replacex(:X))

# pap way without named new col
transform(df, @pap replacex(:X))

```

**Code**

```julia
using MacroTools

ex = :(replacex(:X))
macro pap(ex)
    has_newcol = @capture(ex, newcol_ = rhs_)

    if !has_newcol
        rhs = ex
    end

    # for obtaining symbols
    symbols = QuoteNode[]
    gen_symbols = Symbol[]
    rhs = MacroTools.postwalk(function(x)
        if x isa QuoteNode
            push!(symbols, x)
            push!(gen_symbols, MacroTools.gensym(x.value))
            return gen_symbols[end]
        else
            return x
        end
    end, rhs)

    lhs = Expr(:tuple, gen_symbols...)

    # the fn in
    # :col => fn
    fn = Expr(:->, lhs, rhs)

    # the (:col1, :col2) in
    # the (:col1, :col2) => fn
    cols = Expr(:vect, symbols...)

    if has_newcol
        fn = Expr(:call, :(=>), fn, QuoteNode(newcol))
    end

    Expr(:call, :(=>), cols, fn)
end

```

---

<div class="post-metadata">

### Author: ![xiaodai](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/xiaodai/32/15937_2.png) [@xiaodai](https://discourse.julialang.org/u/xiaodai)
#### Post date: [September 5, 2020, 2:52am UTC](https://discourse.julialang.org/t/a-simple-macro-to-transform-newcol-fn-col-to-col-fn-newcol-friendly-with-dataframes-jl/45893/2 "2020-09-05T02:52:30Z")

</div>

This has been released as [https://github.com/xiaodaigh/PairAsPipe.jl](https://github.com/xiaodaigh/PairAsPipe.jl)
