Expressions separated by semicolon

This happens in a tuple of expressions, when there is a semicolon that separates them:

julia> ex = :(a=1; b=2, c=3)
:(($(Expr(:parameters, :(b=2), :(c=3))), a = 1))

julia> dump(ex)
Expr
  head: Symbol tuple
  args: Array{Any}((2,))
    1: Expr
      head: Symbol parameters
      args: Array{Any}((2,))
        1: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol b
            2: Int64 2
        2: Expr
          head: Symbol kw
          args: Array{Any}((2,))
            1: Symbol c
            2: Int64 3
    2: Expr
      head: Symbol =
      args: Array{Any}((2,))
        1: Symbol a
        2: Int64 1

julia> ex.args[1]
:($(Expr(:parameters, :(b=2), :(c=3))))

julia> ex.args[2]
:(a = 1)

I have failed to find the documentation of this. It seems as if it were to distinguish the keyword arguments (here called “parameters”) when the expressions are arguments of a function (or a macro?).

But if the parameters are the tail of the set of expressions, why is it that they are in the first place of args?

You mean ;? That’s a semi-colon, not a colon.

Semi-colons work just as they do in other languages such as C++ and Java, they are just not required. A semi-colon denotes the end of an expression. For example, using SomePackage; and using SomePackage are the same if they are both followed by a new line. So, for example, in 0.7

(a=1; b=2)

assigns 1 to a and 2 to b and returns b (since it is the last expression). On the other hand

(a=1, b=2)

Is the syntax for a named tuple.

In function arguments ; has a special purpose: to denote keyword arguments.

3 Likes

I meant semicolon, of course.

Thanks for the answer. I understand the difference between separating expressions by comma and semicolon. My question is rather why in (a=1; b=2, c=3) the tuple of expressions that is written after the semicolon (which is not actually a “tuple”, but “parameters”) comes first.

This leads to the following situation when evaluating macros:

julia> macro foo(firstexpression, otherexpressions...)
           print("First: "); println(firstexpression)
           println("Other:"); [println(ex) for ex in otherexpressions]
           quote end
       end
@foo (macro with 1 method)

julia> # This is expected
julia> @foo(sqrt(x), y^2, exp(c))
First: sqrt(x)
Other:
y ^ 2
exp(c)

julia> # But this not!
julia> @foo(sqrt(x); y^2, exp(c))
First: $(Expr(:parameters, :(y ^ 2), :(exp(c))))
Other:
sqrt(x)

The semicolon does have a purpose in the REPL. It suppresses the printing of the expression’s value.
This of course follows on from @ExpandingMan saying the semicolon is the statement separator.

julia> a=1; b=2
2

julia> a=1; b=2;
1 Like

I am not sure this is valid syntax:

julia> (a=1; b=2, c=3)
ERROR: syntax: unexpected semicolon in tuple

julia> VERSION
v"0.7.0-beta2.99"

it is apparently parsed, too, it is just caught later. Eg

julia> function f(x, y, z)
       (a = x; b = y, c =z)
       end
ERROR: syntax: unexpected semicolon in tuple

What were you trying to accomplish with this syntax?

This syntax is used for function calls

julia> :(f(a=1;b=2,c=3)).args
3-element Array{Any,1}:
 :f                                     
 :($(Expr(:parameters, :(b=2), :(c=3))))
 :(a=1)   

So I understand the question is why foo(a; b=1) is parsed as:

Expr(:call, :foo, Expr(:parameters, Expr(:kw, :b, 1)), :a)

and not

Expr(:call, :foo, :a, Expr(:parameters, Expr(:kw, :b, 1)))

?

I haven’t found an answer to this, but decided that historically it might have been an attempt to distinguish them from keyword arguments, e.g. foo(a, b=1):

Expr(:call, :foo, :a, Expr(:kw, :b, 1))

or ellipsis arguments like in foo(a...; b=1)

Expr(:call, :foo, Expr(:parameters, Expr(:kw, :b, 1)), Expr(:..., :a))

or whatever other corner case. Eventually, why not - keyword parameters are quite special in function calls, and although syntactically you have to put them at the end to distinguish from normal arguments, in AST you are free to represent them in whatever form is more convenient for processing.

julia> f(a, b; x=3, y = 4) = a + b + x + y
f (generic function with 1 method)

julia> f(y=1, 2, x=3, 4)
10

Ah, right, I had function definition (i.e. f(a, b; x=3, y = 4)) in mind at the time of writing, there’s no such restriction in function call.

1 Like