# Detect argument is an iterable or a "scalar"

Just `Tuple` would be a `UnionAll` (if tuple was not more primitive than other parametric types), and these are never `isbits` I think.

``````help?> UnionAll
search: UnionAll

UnionAll

A union of types over all values of a type parameter. UnionAll is used to describe
parametric types where the values of some parameters are not known.

Examples
≡≡≡≡≡≡≡≡≡≡

julia> typeof(Vector)
UnionAll

julia> typeof(Vector{Int})
DataType
``````
1 Like

the concretetype and bitstype flags appear to be independent. I wonder if there is currently some type in the system that is bitstype but not concretetype?

``````
@edit isbitstype(Tuple{Int,Int})
# isbitstype(@nospecialize t) = (@_total_meta; isa(t, DataType) && (t.flags & 0x8) == 0x8)

@edit isconcretetype(Vector{Int})

# isconcretetype(@nospecialize(t)) = (@_total_meta; isa(t, DataType) && (t.flags & 0x2) == 0x2)
``````

EDIT: I answer myself the definition requires that the type be of type DataType

julia> isa(Vector, DataType)
false

Still using the legth() function to distinguish cases, if the purpose is to define the names of the files to be generated, you could use a scheme like this

``````julia> function func(xs, args=nothing )
# . . . here comes a lot of preparation to plot figures . . .
s=length(xs)==1 ? "" : f"-p\%3.3d(i)"
pre="myfig"
suf=".png"
for (i, x) in pairs(xs)
# p = plot_a_figure_with_x(x, args )
# savefig(p, "\$pre\$s\$suf") # -> myfig-p001.png, myfig-p002.png, . . .
println("\$pre\$s\$suf", "    x = \$x")
end
end
func (generic function with 2 methods)

julia> func(1:2:6) # iterable
myfig-p001.png    x = 1
myfig-p002.png    x = 3
myfig-p003.png    x = 5

julia> func(3) # scalar
myfig.png    x = 3
``````

or using a flag

``````julia> function func(xs;scalar=false )
# . . . here comes a lot of preparation to plot figures . . .
s=scalar ? "" : f"-p\%3.3d(i)"
pre="myfig"
suf=".png"
for (i, x) in pairs(xs)
# p = plot_a_figure_with_x(x, args )
# savefig(p, "\$pre\$s\$suf") # -> myfig-p001.png, myfig-p002.png, . . .
println("\$pre\$s\$suf", "    x = \$x")
end
end
func (generic function with 2 methods)

julia> func(1:2:6) # iterable
myfig-p001.png    x = 1
myfig-p002.png    x = 3
myfig-p003.png    x = 5

julia> func(3, scalar=true) # scalar
myfig.png    x = 3
``````

Contrary to what you say, `hasmethod` will work perfectly since the goal is to have no error in the plotting program. It will not give an error if a “scalar” goes through the “iterable” part of the code. Also, I think in recent/future versions of julia the cost of `hasmethod` will become very small.

If you look at it from this perspective, then why bother to have a ‘scalar’ part of the code anyway or even check if it is iterable with `hasmethod`? If you pass a single number (a scalar), or a collection of numbers, both can be treated as ‘iterable’. The only reason for having these two parts is that you want the single number `1` to be treated differently from `[1]`, and you will not be able to signal this with just `Number` types and `hasmethod(iterate, ...)`.

Basically, my point is, `hasmethod(iterate, ...)` does not solve the semantic problem for types that implement `iterate` but are often seen as a scalar and you want to treat them as a scalar. The classic example is `String`, you often will want to treat it as a single scalar, but as it implements iterate it will be treated by the plotting method as a sequence of characters.

1 Like

You will get an error if you pass every object to the “iterable” part of the code. For example, a `Symbol` is not iterable. The goal is to have something working for every object, be it a collection or not.