Literals as expressions

Hi,

I’m trying to represent a literal as an Expr object, without success:

julia> :(5) |> typeof
Int64

julia> Meta.parse("5") |> typeof
Int64

julia> function foo(e::Expr) e end
julia> foo(:(5))
ERROR: MethodError: no method matching foo(::Int64)

What I’m trying to do is to store expression objects and later combine them, but I’m unable to store literals. Something along the lines of:

struct Foo
  expr::Expr
end

function combine(op::Symbol, x::Foo, y::Foo)
  return Foo(:($op($(x.expr),$(y.expr))))
end
julia> combine(:+,Foo(:(5*x)),Foo(:(y-1)))
Foo(:(5x + (y - 1)))

julia> combine(:+,Foo(:(5)),Foo(:(y-1)))
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Expr

Is it possible to store literals as Expr objects, or should I hold my expressions as type Any?

Thanks.
-Mike

::Any is probably fine here. Alternatively, you could declare a more specific type alias like:

const ArgType = Union{Expr, Symbol, String, Number}

This will likely have little or no performance benefit over using ::Any, but you might find it helpful in terms of documenting and checking your expected types.

Literals are literal, so you don’t need to convert them to symbols. They are stored as themselves in Expr objects:

julia> dump(:(1 + 2))
Expr
  head: Symbol call
  args: Array{Any}((3,))
    1: Symbol +
    2: Int64 1
    3: Int64 2

No you should use Any if you want to handle anything that can be returned by the parser/lowering. Expr is for, well, expression, and there are syntax that aren’t really expressions, for example literals…

2 Likes

Ok I think I understand now. I can use Union if I know before hand what types of literals I’ll be storing, but if I want to store literals of any type down the road, I really need to use Any. So I think Any is appropriate here. Thanks everyone for your help!

2 Likes