@which not working on .+

Why is this failing?

julia> @which [2 3] .+ [1 2]
ERROR: UndefVarError: .+ not defined

What’s your desired output?

The problem is that at a parser level a .+ b is recognized as just a regular call expression, and the lowering to a broadcast call is actually done at the lowering stage. Therefore, @which thinks this is a call to the function var".+", which, of course, doesn’t exist. You could open an issue, because it should at least give a better error. Dot syntax is lowered to Base.materialize(Base.broadcasted(+, a, b)), so @which could maybe give the location of the Base.materialize call here, but I don’t know how useful that would be.

3 Likes

My intuition is something like a .+ b gets changed to broadcasted_+(a, b), and was hoping it would return something like
broadcasted_+(a::Array{Int64}...)
but now I see it wouldn’t make sense.

The error message could be made to say something like
Did you mean '@which broadcast(+, a, b)'?

4 Likes

I agree it would make sense and be more consistent with similar uses of @which:

julia> @which 1 + 2
+(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:53

julia> @which [1 2] + [3 4]
+(A::Array, Bs::Array...) in Base at arraymath.jl:44

julia> @which [1 2] .+ [3 4]
ERROR: UndefVarError: .+ not defined
Stacktrace:
 [1] top-level scope at REPL[3]:1

I think that the implementation of @which (specifically, the internal InteractiveUtils.gen_call_with_extracted_types) actually calls Meta.lower, but that case just slips through somehow (I didn’t look into this in depth).

In any case, the right behavior would be giving an informative error message.