# How to test functions that operate on abstract types

**URL:** <https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246>\
**Category:** General Usage\
**Created:** [October 23, 2021, 12:56am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246 "2021-10-23T00:56:58Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 12:56am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/1 "2021-10-23T00:56:58Z")

</div>

I have a function `f(x::Vector)`. It’s tested on Vectors and seems to do okay. I looked at the code and think it should also work for all AbstractVectors, but I don’t know how to test this. In general, are there any principles for writing tests for abstract types? More particularly in the case of AbstractVectors and AbstractArrays, is there a list of common mistakes (e.g. 1:length(x) indexing) compiled somewhere? And most particularly, [this is the function](https://github.com/JuliaLang/julia/blob/898142d5b59ab75b586d1fbd4d48eec37b004f40/base/sort.jl#L1214) I’m trying to test.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 23, 2021, 1:12am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/2 "2021-10-23T01:12:49Z")

</div>

You probably intend a function `f(x::AbstractVector)` as a `Vector` is not the same thing as an `AbstractVector`. (oh, I see that is how you have it in the source code linked).

There are many `AbstractVector` types e.g. `subtypes(AbstractVector)`.  
You are likely interested in testing over some set of element types T, like `subtypes(Signed)`, `subtypes(AbstractFloat)`, or maybe general `Real` or `Number` types. On the other hand, you may also want to know your function works with vectors of `Char` and vectors of `String` – or not. What is your intent?

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:18am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/3 "2021-10-23T01:18:46Z")

</div>

Yes. I would like to broaden the function definition from `f(x::Vector)` to `f(x::AbstractVector)`.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 23, 2021, 1:22am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/4 "2021-10-23T01:22:02Z")

</div>

All you need to do in Julia is just specify the type (here the set of types) as `AbstractVector` and your function will be called with any legit realization of an `AbstractVector`. The important part is how to handle such a wide variety of possible inputs in an effective and reasonably concise way.

There some things that make sense for any realization of an AbstractVector, for example, finding its length and determining if the vector is empty. Julia already has `length` and `isempty` that work with AbstractVectors. We can confirm this using the builtin `hasmethod`. To make its use simpler, define

```julia
Base.hasmethod(method, ::Type{T}) where {T} = hasmethod(method, (T,))

```

now

```julia
julia> hasmethod(length, AbstractVector)
true
julia> hasmethod(isempty, AbstractVector)
true

```

You are free to use any of the methods that are predefined for `AbstractVector`s in the design of your tests.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [October 23, 2021, 1:26am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/5 "2021-10-23T01:26:19Z")

</div>

Really the only things to consider is `OffsetArray` and `StaticVector` (if applicable). If those work, pretty much everything else should too.

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:28am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/6 "2021-10-23T01:28:04Z")

</div>

That’s a nice, easy, answer! I’ll test on those two. What makes you think that those two cover everything?

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:31am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/7 "2021-10-23T01:31:14Z")

</div>

> [@JeffreySarnoff](#):
>
> There are many `AbstractVector` types e.g. `subtypes(AbstractVector)` .  
> You are likely interested in testing over some set of element types T, like `subtypes(Signed)` ,

In this case, I am interested in exploring exotic container subtypes rather than element types. I already plan to narrow the element types to the concrete set `Union{Float32, Missing}, Union{Float64, Missing}, Float32, Float64, Missing`

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 23, 2021, 1:31am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/8 "2021-10-23T01:31:24Z")

</div>

This:

[https://github.com/JuliaLang/julia/blob/898142d5b59ab75b586d1fbd4d48eec37b004f40/base/sort.jl#L1220](https://github.com/JuliaLang/julia/blob/898142d5b59ab75b586d1fbd4d48eec37b004f40/base/sort.jl#L1220)

Won’t work for StaticArrays.

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:32am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/9 "2021-10-23T01:32:09Z")

</div>

Wow! I never would have guessed! Why not?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 23, 2021, 1:34am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/10 "2021-10-23T01:34:43Z")

</div>

You cannot overwrite static values.

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [October 23, 2021, 1:36am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/11 "2021-10-23T01:36:10Z")

</div>

They are not mutable, you cannot change each component independently. Actually you can’t have a mutating function (indicated there by the `!`) written for StaticArrays. The “best” you can do is to redefine them and return the new ones.

So, as a rule of thumb, none of the mutating functions are expected to work on static arrays (although they may provide that possiblity if they return the array as well, depending on what the function does).

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [October 23, 2021, 1:37am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/12 "2021-10-23T01:37:25Z")

</div>

Offset arrays cover non-1 based indexing, and static arrays covers the case where you can’t modify the vector. Other than that, the array interface is relatively straightforward. If there’s a bug in something, it would probably be a bug in the array type.

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:44am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/13 "2021-10-23T01:44:04Z")

</div>

Thanks! I forgot that some of them are immutable in addition to being statically sized. I expect that in this case it is okay to declare a function `f!(x::AbstractArray)` and throw a `setindex!(...) not defined` error whenever someone calls `f!(x::SomeImmutibleSubtypeOfAbstractArray)`?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 23, 2021, 1:47am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/14 "2021-10-23T01:47:10Z")

</div>

sure – although that is not strictly necessary … if you don’t , Julia will

```julia
julia> using StaticArrays
julia> staticvec = SVector{4}([1,2,3,4])
julia> staticvec[1] = 100
ERROR: setindex!(::SVector{4, Int64}, value, ::Int) is not defined.

```

This coding style is widely used. When it is important to handle an error or an exception, this style is inappropriate. Otherwise, it works to catch the problem and allows follow up (albeit somewhat in the weeds).

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:48am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/15 "2021-10-23T01:48:06Z")

</div>

It’s nice that the interface is relatively straightforward. For completeness, this feels like a pretty good reference for implementing AbstractArrays: [Interfaces · The Julia Language](https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array), is it also the place to look for knowing what guarantees we have about the behavior of abstract arrays, or perhaps I should look at the docstring of each individual function I call?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [October 23, 2021, 1:50am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/16 "2021-10-23T01:50:56Z")

</div>

People wrote that section just for this purpose. You may examine the docstrings of each function as a way to glean deeper understanding – however the point of an interface is to shield us from having to do that.

---

<div class="post-metadata">

**Author:** ![Lilith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lilith/32/27492_2.png) [@Lilith](https://discourse.julialang.org/u/Lilith)\
**Post date:** [October 23, 2021, 1:51am UTC](https://discourse.julialang.org/t/how-to-test-functions-that-operate-on-abstract-types/70246/17 "2021-10-23T01:51:11Z")

</div>

> [@JeffreySarnoff](#):
>
> sure – although that is not strictly necessary … if you don’t , Julia will

Yes. Exactly. My intention was to leave the function as is with the knowledge that if someone calls it with a `StaticVector` they will get the appropriate result: `ERROR: setindex!(...) is not defined` and it is safe in general. This is in stark contrast to the behavior of `for i in 2:length(x); @inbounds x[i] = x[i-1]` when passed an `OffsetArray`. I want to avoid the latter.
