# Need for explicitly defining subtypes in function arguments?

**URL:** <https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883>\
**Category:** New to Julia\
**Created:** [October 12, 2023, 3:20am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883 "2023-10-12T03:20:43Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 12, 2023, 3:20am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/1 "2023-10-12T03:20:43Z")

</div>

Sorry I’m very new to type systems here.

I’m wondering why you need to state that your function should accept all subtypes in the class hierarchy for nodes which are defined.

```julia
julia> x = collect(1:2)
2-element Vector{Int64}:
 1
 2

julia> g(x::Array{T}) where {T<:Real} = x .* 2
g (generic function with 2 methods)

julia> g(x)
2-element Vector{Int64}:
 2
 4

```

Is there a case where you would ever define a type higher up in the hierarchy - e.g.,

```julia
g(x::Array{Real}) = x .* 2

```

where you wouldn’t want the function to apply to subtypes? I.e., why is the definition above not permitted?

---

<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 12, 2023, 3:26am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/2 "2023-10-12T03:26:51Z")

</div>

The key point is that `Array{Real}` and `Array{Float64}` have completely different memory layouts. `Array{Real}` is an array of pointers to elements who’s type is unknown. By comparison `Array{Float64}` is simply a bunch of `Float64`s next to each other in memory (and you know the element types at compile time). In Julia, no concrete types have subtypes. `Array{Float64}` is not a subtype of `Array{Real}` (i.e. Julia’s type system is invariant).

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [October 12, 2023, 4:23am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/3 "2023-10-12T04:23:13Z")

</div>

> [@hatmatrix](#):
>
> why is the definition above not permitted?

It is

```julia
julia> g(x::Array{Real}) = x .* 2
g (generic function with 1 method)

julia> g(Real[i for i in 1:3])
3-element Vector{Int64}:
 2
 4
 6

```

You just need to call the method with the appropriate type:

```julia
julia> typeof(Real[i for i in 1:3])
Vector{Real} (alias for Array{Real, 1})

```

> [@hatmatrix](#):
>
> `g(x::Array{T}) where {T<:Real} = x .* 2`

If it makes any difference to you, you can shorten this syntax a bit:

```julia
g(x::Array{<:Real}) = x .* 2

```

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 12, 2023, 8:08am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/4 "2023-10-12T08:08:18Z")

</div>

Doesn’t `Float64 <: Real` =\> `true` mean that a concrete type has a subtype? Though `Real` is not an abstract type.

I now see your argument made in Parametric Composite Types section.

[https://docs.julialang.org/en/v1/manual/types/#Parametric-Types](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types)

So it’s really because the implementation in memory and performance is different that `Array{Real}` cannot implicitly accept `Array{Float64}`? I thought there is a layer of abstraction in this but I guess I was mistaken - wo what happens when `g` is defined as `g(x::Array{<:Real})`? Does it just accept `Array{Float64}` arguments but implements it with the inefficient memory layout?

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 12, 2023, 8:12am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/5 "2023-10-12T08:12:35Z")

</div>

Interesting that you can make the data type `Real`- while it has child nodes it’s a concrete data type, but I guess if you were to return a vector with different data types, this is useful?

Thanks for the shortcut… I suppose that makes more sense in this case.

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 12, 2023, 8:31am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/6 "2023-10-12T08:31:16Z")

</div>

I guess it really is about composite types and its effect on memory management, and not about subtypes strictly, since this works:

```julia
julia> a(x::Real) = x * 2
a (generic function with 1 method)

julia> a(2)
4

julia> a.(1:2)
2-element Vector{Int64}:
 2
 4

```

where what is passed is either an `Int64` or `Vector{Int64}`

---

<div class="post-metadata">

**Author:** ![Sevi](https://avatars.discourse-cdn.com/v4/letter/s/c67d28/32.png) [@Sevi](https://discourse.julialang.org/u/Sevi)\
**Post date:** [October 12, 2023, 11:45am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/7 "2023-10-12T11:45:29Z")

</div>

> [@hatmatrix](#):
>
> Doesn’t `Float64 <: Real` =\> `true` mean that a concrete type has a subtype? Though `Real` is not an abstract type.

No:

```julia
julia> isabstracttype(Real)
true

```

* * *

> [@hatmatrix](#):
>
> where what is passed is either an `Int64` or `Vector{Int64}`

Not sure I understand this point. In the first call you pass an `Int` (which is a subtype of `Real`), but in the second one you broadcast, so you can input an iterable, but the function itself will still only accept objects of type `Real` (meaning, any of its subtypes, since there cannot be an instance of `Real`; it is an abstract type).

```julia
julia> a(x::Real) = x * 2
a (generic function with 1 method)

julia> a(2)
4

julia> a(1:2)
ERROR: MethodError: no method matching a(::UnitRange{Int64})

# Broadcasting over anything else than `Real`s fails as well
julia> a.([0.0im, 0.0im])
ERROR: MethodError: no method matching a(::ComplexF64)

```

---

<div class="post-metadata">

**Author:** ![caleb-allen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/caleb-allen/32/14054_2.png) [@caleb-allen](https://discourse.julialang.org/u/caleb-allen)\
**Post date:** [October 12, 2023, 2:21pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/8 "2023-10-12T14:21:18Z")

</div>

> [@Oscar\_Smith](#):
>
> The key point is that `Array{Real}` and `Array{Float64}` have completely different memory layouts.

My understanding is that the memory layout for `Array{Float64}` is that way because `Float64` is a `primitive type` whose size is known.

Is there any similar benefit in using `Array{String}` as opposed to `Array{AbstractString}`, despite the fact that `String` is not a primitive type?

---

<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 12, 2023, 3:14pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/9 "2023-10-12T15:14:28Z")

</div>

yes. The benefit is that by knowing you have `String`s, you know the type of data you get from the array.

---

<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:** [October 12, 2023, 3:37pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/10 "2023-10-12T15:37:42Z")

</div>

> [@caleb-allen](#):
>
> My understanding is that the memory layout for `Array{Float64}` is that way because `Float64` is a `primitive type` whose size is known.

It doesn’t have to be primitive. Immutable structs with immutable field members works as well. So you can create your own composite types that can be stored inline in arrays.

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 12, 2023, 8:18pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/11 "2023-10-12T20:18:23Z")

</div>

Didn’t realize `Real` was an abstract type.

Anyway my point was that `Int64 <: Real` is true but `Array{Int64} <: Array{Real}` is false is counterintuitive.

---

<div class="post-metadata">

**Author:** ![abraemer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abraemer/32/51403_2.png) [@abraemer](https://discourse.julialang.org/u/abraemer)\
**Post date:** [October 12, 2023, 8:31pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/12 "2023-10-12T20:31:47Z")

</div>

What helped me understand the distinction between `Vector{Real}` and `Vector{<:Real}` is the insight that abstract types always denote a collection of types. So like `Real` is the collection of types like `Int64`, `Float64` and so on. Then you can see that `Vector{<:Real}` is also a collection of types. Even clearer if you write it more explicitely as `Vector{T} where T<:Real`. On the other hand, `Vector{Real}` denotes just a single type (the vectors that store anything from the set of `Real`) and is thus a concrete type.

---

<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:** [October 12, 2023, 9:03pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/13 "2023-10-12T21:03:12Z")

</div>

> [@hatmatrix](#):
>
> `Int64 <: Real` is true but `Array{Int64} <: Array{Real}` is false is counterintuitive.

See:

> **[Covariance and contravariance (computer science)](https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science))**
>
> Many programming language type systems support subtyping. For instance, if the type Cat is a subtype of Animal, then an expression of type Cat should be substitutable wherever an expression of type Animal is used.
> Variance is how subtyping between more complex types relates to subtyping between their components. For example, how should a list of Cats relate to a list of Animals? Or how should a function that returns Cat relate to a function that returns Animal?
> Depending on the variance of the ...

---

<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:** [October 12, 2023, 9:03pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/14 "2023-10-12T21:03:37Z")

</div>

> [@hatmatrix](#):
>
> Anyway my point was that `Int64 <: Real` is true but `Array{Int64} <: Array{Real}` is false is counterintuitive

One way to think of it is that `Vector{Real}` is a collection that can hold Ints, Floats, Rational, etc. etc. You can put all sorts of numbers into it. You cannot do that with a `Vector{Int}`. The `Vector{Real}` promises to accept for example the number `2.5`. What happens if you try to put `2.5` into a `Vector{Int}`? That promise is broken.

All technicalities aside, from a purely intuitive standpoint, `Vector{Int}` does not have the properties of a `Vector{Real}`.

---

<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:** [October 12, 2023, 9:06pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/15 "2023-10-12T21:06:50Z")

</div>

This question is actually mentioned in the Julia FAQ: [entry](https://docs.julialang.org/en/v1/manual/faq/#Why-doesn't-it-work-to-declare-foo(bar::Vector%7BReal%7D)-42-and-then-call-foo(%5B1%5D)?). The FAQ entry links to [this](https://docs.julialang.org/en/v1/manual/types/#man-parametric-composite-types) section in the manual for further info.

---

<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:** [October 12, 2023, 9:11pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/16 "2023-10-12T21:11:33Z")

</div>

> [@hatmatrix](#):
>
> what happens when `g` is defined as `g(x::Array{<:Real})`? Does it just accept `Array{Float64}` arguments but implements it with the inefficient memory layout?

The `::Array{<:Real}` type signature/annotation basically translates as “any type `Array{T}` for some `T` that subtypes `Real`”. In the REPL:

```julia-repl
julia> Array{<:Real} == (Array{T} where {T<:Real})
true

```

Note that only abstract types can have subtypes in Julia.

To understand the above example better, also see the documentation on “UnionAll” types: [1](https://docs.julialang.org/en/v1/base/base/#Core.UnionAll) [2](https://docs.julialang.org/en/v1/manual/types/#UnionAll-Types).

> implements it with the inefficient memory layout?

Regarding this part of the question specifically, note that Julia specializes code for the given argument types when compiling the function, so there’s no performance penalty, at least after the compilation is done. See [Monomorphization - Wikipedia](https://en.wikipedia.org/wiki/Monomorphization)

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 13, 2023, 1:48am UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/17 "2023-10-13T01:48:30Z")

</div>

> [@DNF](#):
>
> from a purely intuitive standpoint, `Vector{Int}` does not have the properties of a `Vector{Real}`.

Yes, totally this! I’ve already seen this question coming up a few times here on discourse, and answers typically start from those internal/technical aspect like memory layout. Meanwhile, there’s a clear intuitive explanation that `Vector{Int}` shouldn’t be accepted if function declares `Vector{Real}` – you can only put `2.5` into the latter, not the former. Maybe there’s some canonical place to put this short explanation, so that to link easily afterwards?..

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 13, 2023, 1:07pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/19 "2023-10-13T13:07:57Z")

</div>

my bad

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 13, 2023, 1:09pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/20 "2023-10-13T13:09:34Z")

</div>

Thanks - very great reference to place this into proper context for a non-typist.

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [October 13, 2023, 1:13pm UTC](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883/21 "2023-10-13T13:13:24Z")

</div>

I understand what type-invariance is now but I don’t get your example - if I define a function with argument type `Vector{Real}`, I would expect it to take a collection that contains a value `2.5`, which is not an `Int` but `Float`, which is still a subtype of `Real`. I would not expect that for a function with argument type `Vector{Int}`.

[Next page](https://discourse.julialang.org/t/need-for-explicitly-defining-subtypes-in-function-arguments/104883.md?page=2)
