Initialize multiple variables in one line

Hello,
I would like to initialize multiple variables in one line.
The following code does not work:

a = b = c = Set{Symbol}()

If I do:

push!(a, :test)

all three variables get the same value.
I just want to initialize all of them as empty set of Symbols, but later they shall contain different values.
Any idea how to achieve this in one line?

a = Set{Symbol}(); b = Set{Symbol}(); c = Set{Symbol}()

This should work too:

a, b, c = Set{Symbol}(), Set{Symbol}(), Set{Symbol}()

Perhaps this might work as well

a, b, c = repeat([Set{Symbol}()], 3)

Edit: Nope :cry:

Well, in reality I do not have to initialize three variables, but more. So a shorter notation would be nice to have.

This would be nice. Any idea for a solution that is as short as this one, but works?

How about

a, b, c = [Set{Symbol}() for _ = 1:3]

This doesn not work:

a,b,c =Tuple(repeat([Set{Symbol}()], 3))

Same problem, if I change on of the variables the others get changed too.

a, b, c = [Set{Symbol}() for _ = 1:3]

Looks good! :slight_smile:

Thank you!

Works for me on v1.0.3 and v1.2.0?

julia> a, b, c = repeat([Set{Symbol}()], 3)
3-element Array{Set{Symbol},1}:
 Set([])
 Set([])
 Set([])

julia> a
Set(Symbol[])

julia> b
Set(Symbol[])

julia> c
Set(Symbol[])

julia>   

But if you change one variable, you change all. So not a valid solution.

Save an allocation by not using an array:

a, b, c = (Set{Symbol}() for _ = 1:3)

or

a, b, c = ntuple(_->Set{Symbol}(), 3)

Thank you for your advanced suggestions! :smiley:

The proposed solutions still seem to violate DRY (a bit :wink:) because the number of the variables on the left-hand side of the assignment must match the number on the right-hand side. Unfortunately I don’t see a way to fix this without a macro. Perhaps the following:

macro multidef(ex)
   @assert(ex isa Expr)
   @assert(ex.head == :(=))
   vars = ex.args[1].args
   what = ex.args[2]
   rex = quote end
   for var in vars
      push!(rex.args, :($(esc(var)) = $what))
   end
   rex
end

It can be used as follows:

@multidef a, b, c = Set{Symbol}()

Which has the right outcome:

julia> a,b,c
(Set(Symbol[]), Set(Symbol[]), Set(Symbol[]))

julia> a===b
false

Thanks for this beautiful macro!
But it is only useful if you really use it a lot, otherwise it has too much overhead.

just curious, why didn’t you have the esc around what?

You’re right, it probably makes sense to esc the what as well.

Here it is for the record. I find it super useful, also to learn about writing macros, thanks for sharing!

macro multidef(ex)
    @assert(ex isa Expr)
    @assert(ex.head == :(=))
    vars = ex.args[1].args
    what = ex.args[2]
    rex = quote end
    for var in vars
       push!(rex.args, :( $(esc(var)) = $(esc(what)) ))
    end
    rex
end

What is the benefit of using the second approach, tuple comprehension? How allocation is saved?

julia> testarray() = [Set{Symbol}() for _ = 1:3]

julia> testtuple() = (Set{Symbol}() for _ = 1:3)

julia> (vector = (@allocated testarray()), tuple = (@allocated testtuple()))
(vector = 1552, tuple = 0)

Vectors are not of an unchangeable length, so we can add elements to them; they are stored indirectly. Tuples are fixed in size and other ways, so they are stored directly (immediately in very fast microprocessor-accessible memory).