Confusing parsing behavior

When I try to concatenate 2 ranges, I accidentally write:

[1 : 2; 6 :9]

and there is an Error:

ArgumentError: number of columns of each array must match (got (1, 2))

while these all works:

[1:2; 6:9]
[1 : 2; 6 : 9]
[1 : 2; 6: 9]
6 :9

(Pay attention to these spaces)

Can anyone explain why is it like that? Is it intended or a bug?

1 Like

In the example you’ve shown, I think :9 is treated as a separate symbol, instead as a part of the unit range. On julia1.6.1, comparing [6 :9] and [1 : 2] gives me:

julia> [6 :9]
1Ă—2 Matrix{Int64}:
 6  9
julia> [1 : 2]
1-element Vector{UnitRange{Int64}}:
 1:2

Whereas julia is able to correctly parse expressions like 6:9, 6 : 9, 6: 9 into unit ranges.

Since the number of elements differ, you get a dimension mismatch.

3 Likes

Indeed, you can see the documentation about symbol doing:

help?> Symbol
search: Symbol

  Symbol

  The type of object used to represent identifiers in parsed julia code (ASTs). Also often used as a name or label to identify an entity (e.g. as a dictionary key). Symbols can
  be entered using the : quote operator:

  julia> :name
  :name

  julia> typeof(:name)
  Symbol

  julia> x = 42
  42

  julia> eval(:x)
  42

  Symbols can also be constructed from strings or other values by calling the constructor Symbol(x...).

  Symbols are immutable and should be compared using ===. The implementation re-uses the same object for all Symbols with the same name, so comparison tends to be efficient (it
  can just compare pointers).

  Unlike strings, Symbols are "atomic" or "scalar" entities that do not support iteration over characters.

But actually, typeof(:9) returns Int64, which is not a symbol.

I thought :9 is interpreted as a symbol and get promoted, then everything make sense.
But actually I found :9 is exactly 9 as Int, why is that?

:9 === 9 # true

A Symbol can’t be written like that because they are primarily for representing code as data (julia code can be represented as data in other julia code), and I assume :9 isn’t valid because variable names can’t start with a number. I’m not sure why it evaluates as 9!

But this means your array evaluates as:

[1:2; 6 9]

Which does have 1 and 2 columns, explaining your error.

1 Like

The important thing to note is that :() doesn’t create symbols, it quotes its argument (like quote, but not as a block). If you want to create a symbol, use Symbol:

julia> Symbol(2)
Symbol("2")
3 Likes
julia> :(2) |> typeof
Int64

julia> quote 2 end  |> typeof
Expr

it doesn’t seem to be quoting here?

I don’t want to create a number Symbol, but it seems that julia is interpreting :9 as 9 unexpectedly. Which is the source of this confusing behavior.
But why? I don’t think symbol could explain that…

: is one of the most overloaded and whitespace-sensitive constructs in Julia. So yes, it’s confusing, but shouldn’t pose much of a problem if you’re careful with your whitespace.

2 Likes

quote x end not only quotes x but also wraps x in a begin ... end block (a block expression).

2 Likes