Which symbols are special cased in the same way as `.*`, `.+`, etc

I am working on something in DataFramesMeta where I take an expression

z = :x + :y 

if, like the expression above, the RHS is of the form +(:x, :y), then I can use DataFrames to create the object

[:x, :y] => (+) => :y 

Importantly, we use + rather than create an anonymous function from the expression. If, for example, we had seen

y = :x + :y .* :x

then the expression is not of the form Expr(:call, :f, :x, :y) and therefore I have to define an anonymous function and create something like

function _f(x, y)
    x + y .* x
end
[:x, :y] => _f => :z

this incurs a compile time cost.

Here’s the problem, the expression

z = :x .* :y 

creates an expression

julia> dump(:(:x .* :y))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol .*
    2: QuoteNode
      value: Symbol x
    3: QuoteNode
      value: Symbol y

This looks like I should be able to write

[:x, :y] => (.*) => :z 

However .* is not a function. So using transform on the above expression fails.

Is there anyway for me to know, just by examining the expression, that .* is not a function and I can’t use my little trick to reduce compilation time.

My only thought currently is to look at the first character of string(:.*).

Checkout the latest master! :slightly_smiling_face:

1 Like

Thanks! Can you point me to the issue or PR that does this?

It’s https://github.com/JuliaLang/julia/pull/37583. If you need this for older versions of Julia as well, it would be fairly easy to add support for at least a limited number of operators in Compat.jl, if you are interested in this.

2 Likes

Thanks! This is wonderful! If it’s going to be in 1.6 I would probably just add an if statement for the version and not worry about Compat.

Good to know this will be taken care of!

If anyone is interested in taking a stab at this for Compat.jl, the basic gist is that you would just copy the definition of Base.BroadcastFunction from that linked PR, and then simply do:

for op in [:+, :*]
    @eval const $(Symbol(:., op)) = BroadcastFunction($op)
end

for a bunch of operators. This will allow you to use .* as a standalone function on earlier Julia versions.

3 Likes