Why do functions in Julia have inconsistent attitudes towards arrays? When ind = [true; false], a[ind] is an 1-element Vector{Int64} while reduce(vcat, b[ind]) is just a scalar number.

This means a slight variation on the input parameter of a function that even doesn’t change the format or data type may result in quite different returns. (But I hope function fun can always return a scalar.)

This feature brings considerable inconvenience to coding, one of which is what I have mentioned in this post:

To distinguish between a scalar and an 1-element vector may be logically rigorous, but it seems to deviate from our convention. In particular, Julia, as a programming language that brings code closer to mathematical language (e.g., it supports LaTex characters), just happens to be less “mathematical” here, so why? Is this an advanced design with potential advantages (if so, what are the advantages?), or is it a primitive nature as a programming language?

In the end, I would like to ask everyone for advice on how to deal with such problems in linear algebra programming without making the code overly cumbersome?

julia> function fun(ind)
a = [1; 2]
b = [3 4]
return a[ind]' * b[ind]
end
fun (generic function with 1 method)
julia> fun([true; true])
11
julia> fun([true; false])
3

On the other hand, boolean indexing is consistent and always returns a vector. Further, as explained in the other thread u' * v always gives a scalar for two vectors.

Also, did you intend to define b as a 1 \times 2 matrix or is a comma or semicolon missing?

"""
Return the result of the following expression:
`c' * r`
where `r` is a random vector with a compatible dimension.
"""
function fun2(c)
dim = length(c)
r = rand(dim)
return c' * r
end
fun2([1, 2])
fun2([1])
fun2(1)

What I want to say is that for the expression c^\top r, we mathematically allow c to degenerate into a scalar and the inner product degenerates into a product of two scalars thereby. So I can’t expect the users to be careful to write scalars as single-element vectors when entering function arguments (which is a bit unconventional). Then, who is responsible when the program goes wrong?

Is there a convenient method in Julia that can convert a variable into a vector when it is a scalar? Or I have to use dot(a, b) instead of the natural writing a' * b when calculating the inner product of two vectors?

julia> function fun2(c)
dim = length(c)
r = rand(dim)
return c' * r
end
fun2 (generic function with 1 method)
julia> fun2(c::Number) = fun2([c])
fun2 (generic function with 2 methods)
julia> fun2(1)
0.08685592968950084

The root of the problem here is that you’re using length to determine the size of the output of rand. This is inconsistent with what you’re trying to accomplish. Use size instead:

julia> function fun3(c)
s = size(c)
r = rand(s...)
return c' * r
end
fun3 (generic function with 1 method)
julia> fun3([1, 1])
1.0818115280587444
julia> fun3([1])
0.604859544315378
julia> fun3(1)
0.663513060981263

julia> function f(x::Union{Float64,Int64})
return typeof(x)
end
f (generic function with 1 method)
julia> f(5)
Int64
julia> f(5.0)
Float64
julia> f(3.f0)
ERROR: MethodError: no method matching f(::Float32)
The function `f` exists, but no method is defined for this combination of argument types.
Closest candidates are:
f(::Union{Float64, Int64})
@ Main REPL[18]:1

Sure, if you’re passing a collection/iterator of collections that you want to consolidate. I don’t know of a use when you’re only interested in linear algebra though, and I wouldn’t think of using it in that context either. Julia is not exclusively built for linear algebra.

If there is a function with a matrix A as its input argument, is it my duty to consider the degenerate types of A (e.g., a vector or even a scalar number) or the user’s duty to input the argument strictly in matrix type when invoking the function? Which is more Julian?

The type system distinguishes between matrices, vectors and scalars. Example:

julia> s = 7
7
julia> v = [7, 8]
2-element Vector{Int64}:
7
8
julia> m = [7 8]
1×2 Matrix{Int64}:
7 8
julia> s isa AbstractMatrix
false
julia> v isa AbstractMatrix
false
julia> m isa AbstractMatrix
true

The method dispatch relies on the type system (multiple dispatch). Start using that while writing code.

My argument is (hopefully not the case) that this setup not only leads to some inconsistencies within the Julia language ecosystem (e.g., see this post) but also brings certain inconveniences to programming, especially in the field of mathematics.

I’m trying to use multiple dispatch, but I’m running into some trouble. For example, I have a function that takes multiple input parameters and is implemented as a matrix operation for all the input parameters. However, when calling the function, some or all of the input parameters may degrade to vectors or scalars, which also make sense mathematically. Do I need to separately write degraded form methods for each parameter?