Why is the expression `@foo.x` parsed as `macrocall . foo @x` and not `macrocall @foo .x`?

I know Julia is not at that stage anymore, but i’m curious to know. And just to clarify the macrocall @foo .x, expression, i mean:

Expr
  head: Symbol macrocall
  args: Array{Any}((2,))
    1: Symbol @foo
    2: Expr
        head: Symbol .
        args: Array{Any}((1,))
            Symbol x

Edit: fixed expression mistake

Because whitespace is important in Julia. @foo.x and foo.@x are the same thing (a macro call with 0 arguments) whereas @foo .x is a macro call with 1 argument, the same as @foo(.x).

.x is a valid expression to the parser, it is used for relative imports like using .Foo.

3 Likes

To expand upon what @cjdoris said:

The syntaxes Base.@kwdef and @Base.kwdef are equivalent. They both refer to the macro @kwdef, which is defined in the Base module.

julia> :(Base.@kwdef) == :(@Base.kwdef)
true

julia> dump(:(Base.@kwdef))
Expr
  head: Symbol macrocall
  args: Array{Any}((2,))
    1: Expr
      head: Symbol .
      args: Array{Any}((2,))
        1: Symbol Base
        2: QuoteNode
          value: Symbol @kwdef
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[2]

julia> dump(:(@Base.kwdef))
Expr
  head: Symbol macrocall
  args: Array{Any}((2,))
    1: Expr
      head: Symbol .
      args: Array{Any}((2,))
        1: Symbol Base
        2: QuoteNode
          value: Symbol @kwdef
    2: LineNumberNode
      line: Int64 1
      file: Symbol REPL[3]

However, I think it makes more sense to use the Base.@kwdef syntax.

1 Like

Using @Module.macro instead of Module.@macro strikes me as a bit of a legacy syntax and it’s kind of too bad we kept it for Julia 1.0, but yes, they mean the same thing and parse the same.

3 Likes

This is surprising, I have never considered Mod.@macro to be valid before.