# How to build functions that work efficiently with arguments of different types?

**URL:** <https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504>\
**Category:** General Usage\
**Tags:** juliacomputing, array, function\
**Created:** [November 15, 2021, 3:35pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504 "2021-11-15T15:35:07Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 15, 2021, 3:35pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/1 "2021-11-15T15:35:07Z")

</div>

For implementing sensitivity analysis, I need to build some functions, for example like the one below.

```julia
function just_an_example(a, b, C)
    
    a::Float64
    b::Float64
    C::Vector{Float64}
    return a + b*C
end

```

(This function does not work at this stage and I am aware of that, I have used for loops to compute the iterations related with the Vector. Btw, as I could recall, while using python´s numpy array, the iterations were automatically solved.)

Is there any efficient way to make the function still usable without modification, when next time other arguments like A and B are Vectors, c is a number instead?  
I need you guys open my mind with elegant solutions, thank you!

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [November 15, 2021, 3:38pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/2 "2021-11-15T15:38:59Z")

</div>

```julia
function just_an_example(a, b, C)
    return a + b*C
end

```

Julia will compile efficient code for this whenever it is called with different argument types.

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 15, 2021, 3:45pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/3 "2021-11-15T15:45:35Z")

</div>

![2021-11-15 (2)](https://global.discourse-cdn.com/julialang/original/3X/d/d/dd5fd7ca9dc785d6865c4ff330657f0a5889ec08.png)  
I have tried this approach firstly, actually. However it never worked. Could there be any case-specific issue in my problem?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [November 15, 2021, 3:54pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/5 "2021-11-15T15:54:32Z")

</div>

You are trying to apply `^` to a vector. You probably want to broadcast it `.^`. Fortunately, broadcasting also works applied to a scalar.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [November 15, 2021, 4:06pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/6 "2021-11-15T16:06:46Z")

</div>

By “work” I think you mean you want it to broadcast. Be aware though that this is not the only meaning possible – Julia takes matrices (and vectors) seriously, and while in this case you get an error that raising a vector to a power doesn’t make sense, you can also silently get answers you may not expect. Raising a matrix to a power for instance does make sense, it means repeated `*`:

```julia
julia> [1 2; 3 4]^2 # == [1 2; 3 4] * [1 2; 3 4]
2×2 Matrix{Int64}:
  7 10
 15 22

julia> [1 2; 3 4].^2
2×2 Matrix{Int64}:
 1 4
 9 16

```

Often the right solution will be to broadcast the whole function when you call it. But this won’t work so well with un-packing pairs of arguments. You could change your function to avoid that. Or you can include broadcasting inside your function, which will do nothing in the scalar case:

```julia
julia> f1(x, (y, z)) = x * y^2 / z;

julia> f1(1, (2, 3))
1.3333333333333333

julia> f1(1, (2, [3,4,5])) # this already has a meaning
1×3 transpose(::Vector{Float64}) with eltype Float64:
 0.24 0.32 0.4

julia> f1(1, ([2,3,4], 5)) # as in question
ERROR: MethodError: no method matching ^(::Vector{Int64}, ::Int64)

julia> f1.(1, ([2,3,4], 5)) # can't broadcast the whole function
ERROR: BoundsError: attempt to access Int64 at index [2]

julia> f2(x, (y, z)) = @. x * y^2 / z;

julia> f2(1, (2, 3)) # same as f1
1.3333333333333333

julia> f2(1, (2, [3,4,5])) # NB, this is elementwise ./ not linearsolve /
3-element Vector{Float64}:
 1.3333333333333333
 1.0
 0.8

julia> f2(1, ([2,3,4], 5))
3-element Vector{Float64}:
 0.8
 1.8
 3.2

julia> @code_llvm debuginfo=:none f1(1, (2, 3)) # compare this to next...
define double @julia_f1_9765(i64 signext %0, [2 x i64]* nocapture nonnull readonly align 8 dereferenceable(16) %1) #0 {
top:
  %2 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 0
  %3 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 1
  %4 = load i64, i64* %2, align 8
  %5 = mul i64 %4, %0
  %6 = mul i64 %5, %4
  %7 = sitofp i64 %6 to double
  %8 = load i64, i64* %3, align 8
  %9 = sitofp i64 %8 to double
  %10 = fdiv double %7, %9
  ret double %10
}

julia> @code_llvm debuginfo=:none f2(1, (2, 3)) # ... check that broadcast compiles away
define double @julia_f2_9769(i64 signext %0, [2 x i64]* nocapture nonnull readonly align 8 dereferenceable(16) %1) #0 {
top:
  %2 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 0
  %3 = getelementptr inbounds [2 x i64], [2 x i64]* %1, i64 0, i64 1
  %4 = load i64, i64* %2, align 8
  %5 = mul i64 %4, %0
  %6 = mul i64 %5, %4
  %7 = sitofp i64 %6 to double
  %8 = load i64, i64* %3, align 8
  %9 = sitofp i64 %8 to double
  %10 = fdiv double %7, %9
  ret double %10
}

```

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 16, 2021, 9:33am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/7 "2021-11-16T09:33:43Z")

</div>

Thank you, this is helpful. However, does this (`@.`) mean that I have to write the calculation function in one line? What should I do when I want to write a complicated function with multiple lines and still to be able to make the function work, regardless of the type (either a single number or a vector) of the arguments?

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [November 16, 2021, 9:38am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/8 "2021-11-16T09:38:45Z")

</div>

Can you give an example of such function code?

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 16, 2021, 10:29am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/9 "2021-11-16T10:29:49Z")

</div>

Sure, like the example previously given:  
I can write in one line to make the function `Stokes_number()` work, both when `𝒅_particle` is a single number and a vector.

```julia
Input:
Stokes_number(𝛈, (𝝆_particle, 𝒅_particle), (𝒗_bubble, 𝒅_bubble)) = @. (𝝆_particle * 𝒗_bubble * 𝒅_particle^2) / (9 * 𝛈 * 𝒅_bubble)

test = Stokes_number(0.01, (2.65, 20), (31.6, 0.77*10^-1))

init_vec = [1, 2, 3, 4, 5]
test2= Stokes_number(0.01, (2.65, init_vec), (31.6, 0.77*10^-1))

Output:
Stokes_number (generic function with 1 method)

4.833477633477633e6

5-element Vector{Float64}:
  12083.694083694081
  48334.776334776325
 108753.24675324673
 193339.1053391053
 302092.35209235206

```

However, when my functions have to be more complex in the future, I´d prefer to write them in multiple lines, for example:

```julia
function Stokes_number(𝛈, (𝝆_particle, 𝒅_particle), (𝒗_bubble, 𝒅_bubble))
   ​
   ​𝙆 = (𝝆_particle * 𝒗_bubble * 𝒅_particle^2) / (9 * 𝛈 * 𝒅_bubble)
   ​
   ​return 𝙆
   ​
end

test3 = Stokes_number(0.01, (2.65, 20), (31.6, 0.77*10^-1))
init_vec = [1, 2, 3, 4, 5]
test4 = Stokes_number(0.01, (2.65, init_vec), (31.6, 0.77*10^-1))

Output:
Stokes_number (generic function with 1 method)

4.833477633477633e6

MethodError: no method matching ^(::Vector{Int64}, ::Int64)

```

This time it won´t work. And as @mcabbott mentioned, by coding vector^2 there is a high possibility that something unexpected will come out. I just wanted to know how should I better build my functions, maybe by removing parentheses and avoiding pair-wise arguments?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 16, 2021, 11:10am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/10 "2021-11-16T11:10:57Z")

</div>

```julia
function Stokes_number(𝛈, (𝝆_particle, 𝒅_particle), (𝒗_bubble, 𝒅_bubble))
    K = @. (𝝆_particle * 𝒗_bubble * 𝒅_particle^2) / (9 * 𝛈 * 𝒅_bubble)
    return K
end

```

or even

```julia
function Stokes_number(𝛈, (𝝆_particle, 𝒅_particle), (𝒗_bubble, 𝒅_bubble))
    K = @. (𝝆_particle * 𝒗_bubble * 𝒅_particle^2) / 
        (9 * 𝛈 * 𝒅_bubble)
    return K
end

```

BTW, I got a lot of `syntax: invisible character \u200b near column 5` problems when copy-pasting your code. I love unicode characters, but I think they should be used sparingly, and only when there is no good ASCII equivalent. For example, why use `𝙆, 𝒅, 𝒗` when `K, d, v` is better? Using unicode characters that look almost exactly like ASCII characters, and even have the same meaning, seems like a recipe for trouble.

---

<div class="post-metadata">

**Author:** ![jzr](https://avatars.discourse-cdn.com/v4/letter/j/eb9ed0/32.png) [@jzr](https://discourse.julialang.org/u/jzr)\
**Post date:** [November 16, 2021, 11:16am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/11 "2021-11-16T11:16:02Z")

</div>

Why `return K`?

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 16, 2021, 11:17am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/12 "2021-11-16T11:17:36Z")

</div>

Not sure, but the OP wanted to rephrase the function as a multiline function, as an example, so I didn’t change that.

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 16, 2021, 12:07pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/13 "2021-11-16T12:07:56Z")

</div>

> I got a lot of syntax: invisible character \u200b near column 5 problems when copy-pasting your code. … why use `𝙆, 𝒅, 𝒗` when `K, d, v` is better?

Sorry, I didn´t realize that unicode characters could cause so much trouble. And surely your suggestion is right, I will avoid using them unnecessarily.

Thank you very much for the codes, now the function behaves like I´ve expected.

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 18, 2021, 11:02am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/14 "2021-11-18T11:02:20Z")

</div>

Sorry, I tried your method with further implementations (more complex scenarios). Your method seems only to be able to handle functions with single calculation. In the case of this function below, which needs multiple lines of calculation (for the sake of readability), adding a `@.` before `E0` will cause the `E0 not defined` problem.

I´m wondering how experts would build functions in a way, which regardless of the type of one argument (either it´s a single value or a vector), functions could still be computed automatically. (Of course when two arguments are vector, then it´s another story, I guess the syntax I´ve used here will cause more troubles for vector multiplications.)

```julia
# The GSE model, Generalized Sutherland Equation model
function CollEffi_GSE(d_particle, d_bubble, 𝝆_particle, 𝝆_fluid, Re)
    E0 = 3 * d_particle / d_bubble
    𝛃 = 12 * d_bubble * 𝝆_fluid / (d_particle * (𝝆_particle - 𝝆_fluid) * Re)
    sin_sqr_term = 2 * 𝛃 * ((1 + 𝛃^2)^0.5 - 𝛃)
    cos_term = sqrt(1 - sin_sqr_term)
    term1_in_parent = 4 * E0 * cos_term * (log(3/E0) - 1.8) / (3 * 𝛃)
    term2_in_parent = 2 * (2/3 + cos_term^3/3 - cos_term) / (𝛃 * sin_sqr_term) 

    Ec = E0 * sin_sqr_term * (exp(term1_in_parent - term2_in_parent))
    return Ec
end

Dp_Vector = collect(1:1:100)
test1 = CollEffi_GSE(Dp_Vector, 0.77*1000, 2.65, 1, 240)

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 18, 2021, 3:56pm UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/15 "2021-11-18T15:56:18Z")

</div>

`@.` broadcasts the following complete single expression. If you put it in front of a variable assignment, it converts it to `.=`, which means in-place updating, and can only work if the assigned-to variable already exists.

In a function body you must add as many dots or `@.` as needed, in the right places.

In your current function you should add _none_, though. Instead call `CollEffi_GSE` itself with a dot, as `CollEffi_GSE.()`.

> [@MichaelGao](#):
>
> I´m wondering how experts would build functions in a way, which regardless of the type of one argument (either it´s a single value or a vector), functions could still be computed automatically.

You should normally not do that. Try to write your functions to accept scalars, and then broadcast the function itself, unless the function inherently is a vector function.

---

<div class="post-metadata">

**Author:** ![MichaelGao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/michaelgao/32/27370_2.png) [@MichaelGao](https://discourse.julialang.org/u/MichaelGao)\
**Post date:** [November 23, 2021, 9:51am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/16 "2021-11-23T09:51:03Z")

</div>

I´ve tried to put a dot before each operator and `Base` function, according to the documentation of Julia. That was working as expected, however, is obviously not a convenient approach.

> Instead call `CollEffi_GSE` itself with a dot, as `CollEffi_GSE.()` .

This works so well and I didn´t realize that my own functions can be called with a dot as well like Base.exp.() etc… Only appreciations to you, friend. 💯

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [November 23, 2021, 9:57am UTC](https://discourse.julialang.org/t/how-to-build-functions-that-work-efficiently-with-arguments-of-different-types/71504/17 "2021-11-23T09:57:58Z")

</div>

> [@MichaelGao](#):
>
> I didn´t realize that my own functions can be called with a dot as well

Indeed, every function and operator can be called with a dot! It is one of my favourite Julia features. If you’re interested, the blog post that introduces and perhaps best explains the feature is here: [More Dots: Syntactic Loop Fusion in Julia](https://julialang.org/blog/2017/01/moredots/)
