Collect(a) vs. [a;]

Hi,
I don’t get the difference between collect(a) and [a;] for ranges.

julia> typeof(collect(5:7)) === typeof([5:7;])
true

julia> collect(5:7) == [5:7;]
true

julia> collect(5:7)
3-element Array{Int64,1}:
 5
 6
 7

julia> [5:7;]
3-element Array{Int64,1}:
 5
 6
 7

Yet

julia> collect(5:7) === [5:7;]
false

Is it only because:

julia> @which [5:7;]
vcat(rs::AbstractRange{T}...) where T in Base at range.jl:911

julia> @which collect(5:7)
collect(r::AbstractRange) in Base at range.jl:925

Or maybe I just misunderstood ===.

Moreover, for:

julia> A = Dict([5 => 2, 12 => 9])
Dict{Int64,Int64} with 2 entries:
  5  => 2
  12 => 9

julia> B = keys(A)
Base.KeySet for a Dict{Int64,Int64} with 2 entries. Keys:
  5
  12

I expected [B;] to return the same as collect(B) yet it doesn’t:

julia> [B;]
1-element Array{Base.KeySet{Int64,Dict{Int64,Int64}},1}:
 [5, 12]

Is there a reason for that behavior?
Thanks in advance!
RΓ©mi

EDIT:
It seems to do exactly the same. I will take a look at the function definition.

julia> @benchmark collect(i:j) setup=((i,j)=(rand(1:100), rand(1:100)))
BenchmarkTools.Trial: 
  memory estimate:  80 bytes
  allocs estimate:  1
  --------------
  minimum time:     35.413 ns (0.00% GC)
  median time:      45.078 ns (0.00% GC)
  mean time:        79.823 ns (26.02% GC)
  maximum time:     50.168 ΞΌs (99.50% GC)
  --------------
  samples:          10000
  evals/sample:     993

julia> @benchmark [i:j;] setup=((i,j)=(rand(1:100), rand(1:100)))
BenchmarkTools.Trial: 
  memory estimate:  80 bytes
  allocs estimate:  1
  --------------
  minimum time:     35.374 ns (0.00% GC)
  median time:      45.647 ns (0.00% GC)
  mean time:        79.846 ns (25.69% GC)
  maximum time:     50.445 ΞΌs (99.76% GC)
  --------------
  samples:          10000
  evals/sample:     993

I start with the easy one:

Yes I think so, e.g.:

julia> [5,6,7]==[5,6,7]
true

julia> [5,6,7]===[5,6,7]
false

help?> ===
search: === == !==

  ===(x,y) -> Bool
  ≑(x,y) -> Bool

  Determine whether x and y are identical, in the sense that no program could distinguish them. First the types of x and y are compared. If those are identical, mutable
  objects are compared by address in memory and immutable objects (such as numbers) are compared by contents at the bit level. This function is sometimes called "egal". It
  always returns a Bool value.

julia> ismutable([5,6,7])
true

Array are mutable objects and are therefore compared by address in memory. Thats why above === comparison gives false.

4 Likes

Of course! That’s a strange thing that I wanted === to be == + type equality :confused:

This answer my main question, thanks!

About collect:
https://docs.julialang.org/en/v1/manual/arrays/#man-array-concatenation

If the arguments inside the square brackets are separated by semicolons ( ; ) or newlines instead of commas, then their contents are vertically concatenated together instead of the arguments being used as elements themselves.

julia> @code_lowered collect(5:7)
CodeInfo(
1 ─ %1 = Base.vcat(r)
└──      return %1
)

As you can see: collect in this case is just a vcat, so identical to [5:7;].

1 Like

Ok, that makes sense!
It seems like collect(a) should be preferred over [a;]:

julia> @code_lowered [5:7;]
CodeInfo(
911 1 ──       Core.NewvarNode(:(a))                                                                                                                                                                   β”‚
    β”‚          Core.NewvarNode(:(i))                                                                                                                                                                   β”‚
    β”‚          Core.NewvarNode(:(#temp#@_7))                                                                                                                                                           β”‚
    β”‚    %4  = (Base.convert)(Base.Int, 0)                                                                                                                                                             β”‚
    β”‚          n = (Core.typeassert)(%4, Base.Int)                                                                                                                                                     β”‚
912 β”‚    %6  = rs                                                                                                                                                                                      β”‚
    β”‚          #temp#@_4 = (Base.iterate)(%6)                                                                                                                                                          β”‚
    β”‚    %8  = #temp#@_4 === nothing                                                                                                                                                                   β”‚
    β”‚    %9  = (Base.not_int)(%8)                                                                                                                                                                      β”‚
    └───       goto #4 if not %9                                                                                                                                                                       β”‚
    2 ┄─ %11 = #temp#@_4                                                                                                                                                                               β”‚
    β”‚          ra@_13 = (Core.getfield)(%11, 1)                                                                                                                                                        β”‚
    β”‚    %13 = (Core.getfield)(%11, 2)                                                                                                                                                                 β”‚
913 β”‚    %14 = n                                                                                                                                                                                       β”‚
    β”‚    %15 = (Base.length)(ra@_13)                                                                                                                                                                   β”‚
    β”‚    %16 = %14 + %15                                                                                                                                                                               β”‚
    β”‚    %17 = (Base.convert)(Base.Int, %16)                                                                                                                                                           β”‚
    β”‚          n = (Core.typeassert)(%17, Base.Int)                                                                                                                                                    β”‚
    β”‚          #temp#@_4 = (Base.iterate)(%6, %13)                                                                                                                                                     β”‚
    β”‚    %20 = #temp#@_4 === nothing                                                                                                                                                                   β”‚
    β”‚    %21 = (Base.not_int)(%20)                                                                                                                                                                     β”‚
    └───       goto #4 if not %21                                                                                                                                                                      β”‚
    3 ──       goto #2                                                                                                                                                                                 β”‚
915 4 ── %24 = (Core.apply_type)(Base.Vector, $(Expr(:static_parameter, 1)))                                                                                                                           β”‚
    β”‚          a = (%24)(Base.undef, n)                                                                                                                                                                β”‚
916 β”‚          i = 1                                                                                                                                                                                   β”‚
917 β”‚    %27 = rs                                                                                                                                                                                      β”‚
    β”‚          #temp#@_7 = (Base.iterate)(%27)                                                                                                                                                         β”‚
    β”‚    %29 = #temp#@_7 === nothing                                                                                                                                                                   β”‚
    β”‚    %30 = (Base.not_int)(%29)                                                                                                                                                                     β”‚
    └───       goto #10 if not %30                                                                                                                                                                     β”‚
    5 ┄─ %32 = #temp#@_7                                                                                                                                                                               β”‚
    β”‚          ra@_9 = (Core.getfield)(%32, 1)                                                                                                                                                         β”‚
    β”‚    %34 = (Core.getfield)(%32, 2)                                                                                                                                                                 β”‚
    β”‚    %35 = ra@_9                                                                                                                                                                                   β”‚
    β”‚          #temp#@_8 = (Base.iterate)(%35)                                                                                                                                                         β”‚
    β”‚    %37 = #temp#@_8 === nothing                                                                                                                                                                   β”‚
    β”‚    %38 = (Base.not_int)(%37)                                                                                                                                                                     β”‚
    └───       goto #8 if not %38                                                                                                                                                                      β”‚
    6 ┄─ %40 = ra@_9                                                                                                                                                                                   β”‚
    β”‚          ra@_12 = %40                                                                                                                                                                            β”‚
    β”‚    %42 = #temp#@_8                                                                                                                                                                               β”‚
    β”‚          x = (Core.getfield)(%42, 1)                                                                                                                                                             β”‚
    β”‚    %44 = (Core.getfield)(%42, 2)                                                                                                                                                                 β”‚
918 β”‚          $(Expr(:inbounds, true))                                                                                                                                                                β”‚
    β”‚          (Base.setindex!)(a, x, i)                                                                                                                                                               β”‚
    β”‚          val = x                                                                                                                                                                                 β”‚
    β”‚          $(Expr(:inbounds, :pop))                                                                                                                                                                β”‚
    β”‚          val                                                                                                                                                                                     β”‚
919 β”‚          i = i + 1                                                                                                                                                                               β”‚
    β”‚          #temp#@_8 = (Base.iterate)(%35, %44)                                                                                                                                                    β”‚
    β”‚    %52 = #temp#@_8 === nothing                                                                                                                                                                   β”‚
    β”‚    %53 = (Base.not_int)(%52)                                                                                                                                                                     β”‚
    └───       goto #8 if not %53                                                                                                                                                                      β”‚
    7 ──       goto #6                                                                                                                                                                                 β”‚
    8 ──       #temp#@_7 = (Base.iterate)(%27, %34)                                                                                                                                                    β”‚
    β”‚    %57 = #temp#@_7 === nothing                                                                                                                                                                   β”‚
    β”‚    %58 = (Base.not_int)(%57)                                                                                                                                                                     β”‚
    └───       goto #10 if not %58                                                                                                                                                                     β”‚
    9 ──       goto #5                                                                                                                                                                                 β”‚
921 10 ─       return a                                                                                                                                                                                β”‚
)

julia> @code_lowered collect(5:7)
CodeInfo(
925 1 ─ %1 = (Base.vcat)(r)                                                                                                                                                                            β”‚
    └──      return %1                                                                                                                                                                                 β”‚
)

Or not!

julia> @code_lowered vcat(5:7)
CodeInfo(
911 1 ──       Core.NewvarNode(:(a))                                                                                                                                                                   β”‚
    β”‚          Core.NewvarNode(:(i))                                                                                                                                                                   β”‚
    β”‚          Core.NewvarNode(:(#temp#@_7))                                                                                                                                                           β”‚
    β”‚    %4  = (Base.convert)(Base.Int, 0)                                                                                                                                                             β”‚
    β”‚          n = (Core.typeassert)(%4, Base.Int)                                                                                                                                                     β”‚
912 β”‚    %6  = rs                                                                                                                                                                                      β”‚
    β”‚          #temp#@_4 = (Base.iterate)(%6)                                                                                                                                                          β”‚
    β”‚    %8  = #temp#@_4 === nothing                                                                                                                                                                   β”‚
    β”‚    %9  = (Base.not_int)(%8)                                                                                                                                                                      β”‚
    └───       goto #4 if not %9                                                                                                                                                                       β”‚
    2 ┄─ %11 = #temp#@_4                                                                                                                                                                               β”‚
    β”‚          ra@_13 = (Core.getfield)(%11, 1)                                                                                                                                                        β”‚
    β”‚    %13 = (Core.getfield)(%11, 2)                                                                                                                                                                 β”‚
913 β”‚    %14 = n                                                                                                                                                                                       β”‚
    β”‚    %15 = (Base.length)(ra@_13)                                                                                                                                                                   β”‚
    β”‚    %16 = %14 + %15                                                                                                                                                                               β”‚
    β”‚    %17 = (Base.convert)(Base.Int, %16)                                                                                                                                                           β”‚
    β”‚          n = (Core.typeassert)(%17, Base.Int)                                                                                                                                                    β”‚
    β”‚          #temp#@_4 = (Base.iterate)(%6, %13)                                                                                                                                                     β”‚
    β”‚    %20 = #temp#@_4 === nothing                                                                                                                                                                   β”‚
    β”‚    %21 = (Base.not_int)(%20)                                                                                                                                                                     β”‚
    └───       goto #4 if not %21                                                                                                                                                                      β”‚
    3 ──       goto #2                                                                                                                                                                                 β”‚
915 4 ── %24 = (Core.apply_type)(Base.Vector, $(Expr(:static_parameter, 1)))                                                                                                                           β”‚
    β”‚          a = (%24)(Base.undef, n)                                                                                                                                                                β”‚
916 β”‚          i = 1                                                                                                                                                                                   β”‚
917 β”‚    %27 = rs                                                                                                                                                                                      β”‚
    β”‚          #temp#@_7 = (Base.iterate)(%27)                                                                                                                                                         β”‚
    β”‚    %29 = #temp#@_7 === nothing                                                                                                                                                                   β”‚
    β”‚    %30 = (Base.not_int)(%29)                                                                                                                                                                     β”‚
    └───       goto #10 if not %30                                                                                                                                                                     β”‚
    5 ┄─ %32 = #temp#@_7                                                                                                                                                                               β”‚
    β”‚          ra@_9 = (Core.getfield)(%32, 1)                                                                                                                                                         β”‚
    β”‚    %34 = (Core.getfield)(%32, 2)                                                                                                                                                                 β”‚
    β”‚    %35 = ra@_9                                                                                                                                                                                   β”‚
    β”‚          #temp#@_8 = (Base.iterate)(%35)                                                                                                                                                         β”‚
    β”‚    %37 = #temp#@_8 === nothing                                                                                                                                                                   β”‚
    β”‚    %38 = (Base.not_int)(%37)                                                                                                                                                                     β”‚
    └───       goto #8 if not %38                                                                                                                                                                      β”‚
    6 ┄─ %40 = ra@_9                                                                                                                                                                                   β”‚
    β”‚          ra@_12 = %40                                                                                                                                                                            β”‚
    β”‚    %42 = #temp#@_8                                                                                                                                                                               β”‚
    β”‚          x = (Core.getfield)(%42, 1)                                                                                                                                                             β”‚
    β”‚    %44 = (Core.getfield)(%42, 2)                                                                                                                                                                 β”‚
918 β”‚          $(Expr(:inbounds, true))                                                                                                                                                                β”‚
    β”‚          (Base.setindex!)(a, x, i)                                                                                                                                                               β”‚
    β”‚          val = x                                                                                                                                                                                 β”‚
    β”‚          $(Expr(:inbounds, :pop))                                                                                                                                                                β”‚
    β”‚          val                                                                                                                                                                                     β”‚
919 β”‚          i = i + 1                                                                                                                                                                               β”‚
    β”‚          #temp#@_8 = (Base.iterate)(%35, %44)                                                                                                                                                    β”‚
    β”‚    %52 = #temp#@_8 === nothing                                                                                                                                                                   β”‚
    β”‚    %53 = (Base.not_int)(%52)                                                                                                                                                                     β”‚
    └───       goto #8 if not %53                                                                                                                                                                      β”‚
    7 ──       goto #6                                                                                                                                                                                 β”‚
    8 ──       #temp#@_7 = (Base.iterate)(%27, %34)                                                                                                                                                    β”‚
    β”‚    %57 = #temp#@_7 === nothing                                                                                                                                                                   β”‚
    β”‚    %58 = (Base.not_int)(%57)                                                                                                                                                                     β”‚
    └───       goto #10 if not %58                                                                                                                                                                     β”‚
    9 ──       goto #5                                                                                                                                                                                 β”‚
921 10 ─       return a                                                                                                                                                                                β”‚
)

They are the same. Both is at the end vcat.

1 Like

Yeah, personally I would go for collect, since turning an iterable into a Vector (or more generally an Array) is exactly its purpose, so in my opinion the code is more readable that way. I wouldn’t really worry about comparing implementations unless it turned out to be a performance bottleneck (in which case you might want to avoid allocating arrays anyway, depending on the situation).

1 Like

I see it the same way. Actually I had to look up for the [5:7;] syntax because I wasn’t aware of this subtilty.

1 Like

I agree!
This notation is used in julia testings:
https://github.com/JuliaLang/julia/blob/46cf572773b05d8f4ab74705b139f7a921227c02/test/sorting.jl#L36

Code should ideally signal intent, not rely on a corner case. I think that collect is vastly preferable.

4 Likes

I also agree and opened an issue to suggest the change (https://github.com/JuliaLang/julia/issues/37698)

1 Like