How to pass set of attributes to command

how to pass set of attributes to command

How to pass a set of attributes to a command by having all attributes predefined in an array (?), string (?), whatever (?) ?
A general solution is preferred to learn about, but maybe there are only package specific solutions?

For example, some graphical plotting code using GLMakie.jl could simplified be written like this:

using GLMakie
# ... much code goes here ...
scatter(x1, y2, color = :red, markersize = 8)
# ... much code goes here ...
scatter!(x2, y2, color = :green, markersize = 2)
# ... much code goes here ...
scatter!(x3, y3, color = :red, markersize = 8)

Changing my decision on the attributes “color” and “markersize” requires to find all positions in my code where the attributes in question have been used and individually change them there. But it would be more convenient for me to maintain my code in a way allowing me to easily find close to the top of the code definitions of sets of attributes, which can then be reused later in the code. For example, I would like to structure my code like shown in the following, and please note that I did not find which syntax to use for it and the correct syntax which has to be used in the following code is actually what my question is about:

using GLMakie
# ... very few code goes here ...
myAttributes_A = [ "color = :red", "markersize = 8" ]
myAttributes_B = [ "color = :green", "markersize = 2" ]
# ... much code goes here ...
scatter(x1, y2, myAttributes_A)
# ... much code goes here ...
scatter!(x2, y2, myAttributes_B)
# ... much code goes here ...
scatter!(x3, y3, myAttributes_A)

Besides searching for a solution for the commands from the GLMakie package, I assume that in Julia something like this will follow a general recommended syntax, right? Or does this always depends on the specific command implementation?

named tuples and the splat operator

julia> function f(a; b=1, c=2)
       println("$a $b $c")
       end
f (generic function with 1 method)

julia> f(0)
0 1 2

julia> f(0; (b=10, c=11)...)
0 10 11

julia> f(0; (c=10, b=11)...)
0 11 10

julia> f(0; (c=10,)...)
0 1 10
3 Likes

Thanks, but this is not what I am struggling with. Your example is actually the code organization what I wish to avoid. I do NOT want to write b and c (or more tuples) into each call of the function, but I want that the tuples b and c (or more tuples) have beforehand been defined outside of the function, and both (or more of the tuples) alltogether become inserted from 1 carrier (the carrier being an array of tuples or something which would serve the purpose).
I want something similar like it exits for working with strings in the println command:

insertThis = "a lot"
println("Thanks ",insertThis)

but need insertThis containing various tuples, and instead of println applying the insertion to a command like
scatter(x, y, tuple1, tuple2, tuple3)

So, I am in search for something like:

insertThis = [ tuple1; tuple2; tuple3 ]
scatter(x, y, insertThis)

obtaining the effect of scatter(x, y, tuple1, tuple2, tuple3)

I think you did not understand lawless-m’s suggestion.

julia> attribute_set_A = (; color = :red)
(color = :red,)

julia> attribute_set_B = (; markersize = 2)
(markersize = 2,)

julia> f(; color = :black, markersize = 1) = @show color, markersize
f (generic function with 1 method)

julia> f(; attribute_set_A...)
(color, markersize) = (:red, 1)
(:red, 1)

julia> f(; attribute_set_B...)
(color, markersize) = (:black, 2)
(:black, 2)

julia> f(; merge(attribute_set_A, attribute_set_B)...)
(color, markersize) = (:red, 2)
(:red, 2)

If you have an array of NamedTuples you can either do merge(nm_array...)... or foldl(merge, nm_array)...

2 Likes

This indeed works, thanks a lot for your step by step example.
For a first time user it is confusing how the " ; " has to be used, because to me known scatter(x, y, markersize=2) does show a " , " behind the " y " while your function, for example f(a; b=1, c=2), uses already " ; " behind the " a ". It is also confusing the usage of the " … " operator. I’ll still have to study the docs for fully understanding how both these details work.
However, it works nicely!

The solution translates to my particular code as:

using GLMakie

x = range(1, 10, length=50);
y1 = sin.(x);
y2 = cos.(x);

alternativeAttributes = (; color = :red, markersize = 5);

scatter(x, y1, color = :green, markersize = 9)
scatter!(x, y2; alternativeAttributes...)

current_figure()
1 Like

I do understand, the ; for keyword parameter separation and the ... (which is both the slurping and the splatting operators) are often confusing for someone that has not seen them before in other languages.

I do want to point out, however, that ; is rarely needed for keyword argument/parameters separation: only when the function has only keyword parameters and they are passed by splatting that they are truly needed. Otherwise, Julia allows both ‘,’ and ‘;’ to separate keyword arguments/parameters, and most people use ‘,’. I use ‘;’ because of stylist preferences and because I preferred the language to have never have allowed ‘,’ in this context and sticked to ‘;’.

Adding to the previous code, if I have at least one positional parameter I can write:

julia> f(x, color = :black, markersize = 1) = @show x, color, markersize
f (generic function with 4 methods)

julia> f("abc", merge(attribute_set_A, attribute_set_B)...)
(x, color, markersize) = ("abc", :red, 2)
("abc", :red, 2)

The ... splatting operator is basically a: “do not treat this as one container object with multiple elements inside but instead as all the elements were there outside any container”.

I think the manual sections you want are:

  1. https://docs.julialang.org/en/v1/manual/faq/#The-two-uses-of-the-…-operator:-slurping-and-splatting – FAQ section that confirms many beginners find ... confusing.
  2. Keyword arguments – The manual section on keyword arguments.
2 Likes

I keep the ; at the call site to make my intentions clear to future readers.

2 Likes

Thanks a lot for the explanation, and also for the very helpful links to the documentation!

Thanks also for your explanations! Now that I understand better the solution, I also understand better your answer. And I like the idea to keep the ; at the call site for future reading.

1 Like