# Type Definition of Array Arguments to Functions

**URL:** https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372
**Category:** General Usage
**Tags:** type-stability, function-parameters
**Created:** [September 13, 2024, 1:18pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372 "2024-09-13T13:18:19Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![freestatelabs](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@freestatelabs](https://discourse.julialang.org/u/freestatelabs)
#### Post date: [September 13, 2024, 1:18pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/1 "2024-09-13T13:18:19Z")

</div>

Hi, for a project I’m working on, I defaulted to defining my functions with input arrays with data types as Float64, i.e.

```julia
function foo(vec::Vector{Float64})
    # do stuff 
end

```

However, I realized later that this was a mistake, as sometimes I’d have input arrays of Integers. So, thinking that I could use a supertype here, I tried defining my functions like this:

```julia
function bar(vec::Vector{Number})
   # Do the same stuff 
end

```

However, I get this error:

```julia
julia> vec = [1,2,3]
3-element Vector{Int64}:
 1
 2
 3

julia> bar(vec)
ERROR: MethodError: no method matching bar(::Vector{Int64})

Closest candidates are:
  bar(::Matrix{Number})

```

Since `Int64` is a subtype of `Number`, shouldn’t this work just fine? Are there best practices I should be aware of when defining input types for function arguments?

---

<div class="post-metadata">

### Author: ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)
#### Post date: [September 13, 2024, 1:23pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/2 "2024-09-13T13:23:19Z")

</div>

Use `<:Number`

```julia
julia> function foo(a::Vector{Number}) end;

julia> foo([1.0, 2.0, 3.0])
ERROR: MethodError: no method matching foo(::Vector{Float64})

Closest candidates are:
  foo(::Vector{Number})
   @ Main REPL[7]:1

Stacktrace:
 [1] top-level scope
   @ REPL[8]:1

julia> function bar(a::Vector{<:Number}) end;

julia> bar([1.0, 2.0, 3.0]) # worked

```

---

<div class="post-metadata">

### Author: ![screw\_dog](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/screw_dog/32/48119_2.png) [@screw\_dog](https://discourse.julialang.org/u/screw_dog)
#### Post date: [September 13, 2024, 1:27pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/3 "2024-09-13T13:27:58Z")

</div>

Just want to add that over specifying type information is somewhat of an anti-pattern in Julia, especially outside of library code.

It is only necessary to specify types at all if you are taking advantage of dispatch ie you want to have multiple methods for the same function that work differently for different types. I would caution against adding any type information unless actually necessary

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 13, 2024, 1:29pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/4 "2024-09-13T13:29:43Z")

</div>

This is covered in the manual [here](https://docs.julialang.org/en/v1/manual/types/#man-parametric-composite-types).

---

<div class="post-metadata">

### Author: ![freestatelabs](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@freestatelabs](https://discourse.julialang.org/u/freestatelabs)
#### Post date: [September 13, 2024, 2:13pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/5 "2024-09-13T14:13:06Z")

</div>

> [@screw\_dog](#):
>
> Just want to add that over specifying type information is somewhat of an anti-pattern in Julia, especially outside of library code.
> 
> It is only necessary to specify types at all if you are taking advantage of dispatch ie you want to have multiple methods for the same function that work differently for different types. I would caution against adding any type information unless actually necessary

I think my question is a great example of why it’s an anti-pattern. 😂

This holds true for function definitions, right? But I’m getting confused with the overlap with type definitions. For example, if I define:

```julia
abstract type Data end
struct DataA <: Data vec::Vector end 
struct DataB <: Data vec::Vector{Number} end

```

and then a series of contrived test functions, one of which operates on both structs, and the other two are subtype-specific:

```julia
function test_data(data::Data) 
    for i in eachindex(data.vec)
        a = data.vec[i]   
    end
end

function test_dataA(data::DataA)
    for i in eachindex(data.vec)
        a = data.vec[i]   
    end
end

function test_dataB(data::DataB)
    for i in eachindex(data.vec)
        b = data.vec[i]   
    end
end

```

Every usage of `DataA` (the one that does _not_ specify a composite type for `vec::Vector`) results in memory allocations (why 1489 in this case, and not 1000?) whereas `vec::Vector{Number}` does not:

```julia
A = DataA(rand(1000))
B = DataB(rand(1000))
using BenchmarkTools 

```

```julia
julia> @btime test_data($A)
  15.916 μs (1489 allocations: 23.27 KiB)

julia> @btime test_data($B)
  321.708 ns (0 allocations: 0 bytes)

julia> @btime test_dataA($A)
  16.166 μs (1489 allocations: 23.27 KiB)

julia> @btime test_dataB($B)
  321.659 ns (0 allocations: 0 bytes)

```

Thank you!

---

<div class="post-metadata">

### Author: ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)
#### Post date: [September 13, 2024, 2:21pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/6 "2024-09-13T14:21:16Z")

</div>

> [@freestatelabs](#):
>
> Every usage of `DataA` (the one that does _not_ specify a composite type for `vec::Vector`) results in memory allocations

Covered in the manual [here](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-abstract-container).

---

<div class="post-metadata">

### Author: ![nilshg](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nilshg/32/2283_2.png) [@nilshg](https://discourse.julialang.org/u/nilshg)
#### Post date: [September 13, 2024, 2:23pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/7 "2024-09-13T14:23:05Z")

</div>

Just to be clear you want something like

```julia
struct DataC{T} where T <: Data
    vec::Vector{T}
end

```

which makes the following difference for type inference:

```julia
julia> @code_warntype test_data(A)
MethodInstance for test_data(::DataA)
  from test_data(data::Data) @ Main REPL[5]:1
Arguments
  #self#::Core.Const(test_data)
  data::DataA
Locals
  @_3::Union{Nothing, Tuple{Int64, Int64}}
  i::Int64
  a::Any
(...)

julia> C = DataC(rand(1000));

julia> @code_warntype test_data(C)
MethodInstance for test_data(::DataC2{Float64})
  from test_data(data::Data) @ Main REPL[5]:1
Arguments
  #self#::Core.Const(test_data)
  data::DataC2{Float64}
Locals
  @_3::Union{Nothing, Tuple{Int64, Int64}}
  i::Int64
  a::Float64

```

---

<div class="post-metadata">

### Author: ![screw\_dog](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/screw_dog/32/48119_2.png) [@screw\_dog](https://discourse.julialang.org/u/screw_dog)
#### Post date: [September 13, 2024, 2:25pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/8 "2024-09-13T14:25:57Z")

</div>

It is usually advised to have concrete types in structs - and to use type parameters if necessary to achieve this. In this example both are actually abstract types (since `Number` is abstract) but it probably allows some inference?

But honestly, I feel like this is probably premature optimization. I would suggest simply defining functions like `eachindex` and `getindex` on your types and writing your functions generically. Then implementation details of these types can be changed later when performance issues can actually be measured.

(I feel like the Julia community is so used to thinking about performance that we tend to reach for performant practices early in development long before any sensible profiling can be done. But that’s just my ranty opinion so take with a grain of salt)

---

<div class="post-metadata">

### Author: ![freestatelabs](https://avatars.discourse-cdn.com/v4/letter/f/9de0a6/32.png) [@freestatelabs](https://discourse.julialang.org/u/freestatelabs)
#### Post date: [September 13, 2024, 2:36pm UTC](https://discourse.julialang.org/t/type-definition-of-array-arguments-to-functions/119372/9 "2024-09-13T14:36:42Z")

</div>

Thanks for the detailed explanation here.

The goal of my project is to see how fast I can get a particular type of calculation to run - i.e. the innovation is speed, not writing something that doesn’t exist yet. In doing so, I’ve spent _a lot_ of time trying to teach myself how to write more performant Julia code, which has resulted in…my project forever being incomplete.

So I agree with your take on this - first write something sensible that runs, and then optimize later once you have good measurements on its end-use/real-world performance.
