# Inherit from a concrete type

**URL:** <https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291>\
**Category:** New to Julia\
**Created:** [March 7, 2024, 12:34pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291 "2024-03-07T12:34:23Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![Matthijs\_1971](https://avatars.discourse-cdn.com/v4/letter/m/bb73d2/32.png) [@Matthijs\_1971](https://discourse.julialang.org/u/Matthijs_1971)\
**Post date:** [March 7, 2024, 12:34pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/1 "2024-03-07T12:34:23Z")

</div>

```
function func_a(arg::Vector{<: Bool})
  println(arg)
end

function func_b(arg::Vector{Bool})
  println(arg)
end

v = [true, false, false, true]
func_a(v)
func_b(v)

```

Does it make sense to use the \<: operator on a concrete type like Bool? What is the difference between both functions if any? In this case, Bool is a concrete type so nothing can ever be derived from it.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 7, 2024, 12:54pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/2 "2024-03-07T12:54:27Z")

</div>

It is impossible for a concrete type to subtype a different concrete type. Technically subtyping isn’t inheritance because structs are not classes. `Vector{<:Bool}` is short for `Vector{T} where T<:Bool`; that’s just a type parameter constraint, and the only practical concrete `T` is indeed `Bool`. `Union{}<:Bool`, but `Union{}` is uninstantiable and abstract.

As shown, an abstract type can actually subtype a concrete type. The practical usage is type selectors, e.g. `Type{Bool} <: DataType`. Many types are instances of `DataType`, including itself. However, it can be useful to dispatch more specifically on the abstract `Type{Bool}` than on the concrete `DataType`, for example `function foo(::Type{Bool})...` would only work on calls `foo(Bool)`. Besides this, you can pretty much consider the subtyping hierarchy as a tree with abstract branch nodes and concrete leaf nodes.

---

<div class="post-metadata">

**Author:** ![Matthijs\_1971](https://avatars.discourse-cdn.com/v4/letter/m/bb73d2/32.png) [@Matthijs\_1971](https://discourse.julialang.org/u/Matthijs_1971)\
**Post date:** [March 8, 2024, 12:30pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/3 "2024-03-08T12:30:00Z")

</div>

Thanks for your answer, but I fail to see some of it relates to my questions.

```
function func_a(arg::Vector{<: Bool})
  println(arg)
end

function func_b(arg::Vector{Bool})
  println(arg)
end

function func_c(arg::Vector{T}) where T <: Bool
  println(arg)
end

v = [true, false, false, true]

@code_warntype func_a(v)

@code_warntype func_b(v)

@code_warntype func_c(v)

```

Output:

```
MethodInstance for func_a(::Vector{Bool})
  from func_a(arg::Vector{<:Bool}) @ Main ...
Arguments
  #self#::Core.Const(func_a)
  arg::Vector{Bool}
Body::Nothing
1 ─ %1 = Main.println(arg)::Core.Const(nothing)
└── return %1

MethodInstance for func_b(::Vector{Bool})
  from func_b(arg::Vector{Bool}) @ Main ...
Arguments
  #self#::Core.Const(func_b)
  arg::Vector{Bool}
Body::Nothing
1 ─ %1 = Main.println(arg)::Core.Const(nothing)
└── return %1

MethodInstance for func_c(::Vector{Bool})
  from func_c(arg::Vector{T}) where T<:Bool @ Main ...
Static Parameters
  T = Bool
Arguments
  #self#::Core.Const(func_c)
  arg::Vector{Bool}
Body::Nothing
1 ─ %1 = Main.println(arg)::Core.Const(nothing)
└── return %1

julia> 

```

The output related to `func_a` and `func_b` is equal. To me that suggests that the use of `<:` does not make `func_a` different from `func_b`. So why is using `<:` in this situation allowed?

The new function `func_c` allows for the use of `T` in the function body, but the `arg` value is `Vector{Bool}` for all three. To me this suggests that all three functions can take the exact same argument object and nothing else. Correct?

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [March 8, 2024, 10:50pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/4 "2024-03-08T22:50:40Z")

</div>

Correct. Although Julia considers `Vector{Bool}` to be more specific than `Vector{<: Bool}`. Also see that Julia regards A, C, and D below as having identical signatures. However, only B will be called.

```julia-repl
julia> foo(arg::Vector{<: Bool}) = :A
foo (generic function with 1 method)

julia> foo(arg::Vector{Bool}) = :B
foo (generic function with 2 methods)

julia> foo(arg::Vector{T} where T <: Bool) = :C
foo (generic function with 2 methods)

julia> foo(arg::Vector{T}) where T <: Bool = :D
foo (generic function with 2 methods)

julia> methods(foo)
# 2 methods for generic function "foo" from Main:
 [1] foo(arg::Vector{Bool})
     @ REPL[11]:1
 [2] foo(arg::Vector{T}) where T<:Bool
     @ REPL[13]:1

julia> foo([true])
:B

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [March 9, 2024, 1:47am UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/5 "2024-03-09T01:47:58Z")

</div>

> [@Matthijs\_1971](#):
>
> Thanks for your answer, but I fail to see some of it relates to my questions.

Only the first paragraph directly addresses your question. The second explains how abstract types can subtype concrete types because it goes against the common misconception that concrete types are leaf nodes in the type hierarchy. It is related to the first paragraph because the distinction between `Vector{Bool}` and `Vector{<:Bool}` is that the latter includes abstract parameters like `Vector{Union{}}`.

> [@Matthijs\_1971](#):
>
> The output related to `func_a` and `func_b` is equal. To me that suggests that the use of `<:` does not make `func_a` different from `func_b`.

They are (see mkitti’s comment showing the `:B` method is different). Type inference in `@code_warntype` is done for call signatures, not method signatures. All of your reports had the call signatures `func_X(::Vector{Bool})` from the argument `v isa Vector{Bool}` you provided.

> [@mkitti](#):
>
> Also see that Julia regards A, C, and D below as having identical signatures.

Also note that this concerns what the method table considers overwriting. There are practical differences. The `:C` method’s `T` is not usable outside the parametric type, but in more complicated parametric types you can use that to equate multiple parameters. The `:D` method’s `T` becomes a static parameter for the method body (you can’t reassign it like you could a local variable), and this can be used to force the compiler to specialize on some arguments in the exceptional cases it doesn’t.

---

<div class="post-metadata">

**Author:** ![Matthijs\_1971](https://avatars.discourse-cdn.com/v4/letter/m/bb73d2/32.png) [@Matthijs\_1971](https://discourse.julialang.org/u/Matthijs_1971)\
**Post date:** [March 11, 2024, 4:02pm UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/7 "2024-03-11T16:02:54Z")

</div>

> Correct. Although Julia considers `Vector{Bool}` to be more specific than `Vector{<: Bool}`. Also see that Julia regards A, C, and D below as having identical signatures. However, only B will be called.

Brilliant. So casually typing `<:` in a signature can lead to problems that are really hard to find if there is a function with the same signature but missing the `<:`. Whatever is changed in the function with `<:` is never executed if the twin is implemented too. Benny points out that with the `<:` also vectors of `Union{}` can be accepted with `<:`, but that use case seems rare, and if tried it is likely to crash the program when elements of the non-existing vector are addressed. So casually mixing prototypes with `<:` and without `<:` is confusing and it requires understanding of the specific rule.

> They are (see mkitti’s comment showing the `:B` method is different). Type inference in `@code_warntype` is done for call signatures, not method signatures. All of your reports had the call signatures `func_X(::Vector{Bool})` from the argument `v isa Vector{Bool}` you provided.

Ah, thanks. I think what you mean is that if I use the `@code_warntype` macro the argument matters. I have done too much C in my lifetime.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [March 12, 2024, 10:28am UTC](https://discourse.julialang.org/t/inherit-from-a-concrete-type/111291/8 "2024-03-12T10:28:17Z")

</div>

> [@Matthijs\_1971](#):
>
> if tried it is likely to crash the program when elements of the non-existing vector are addressed

You can only create `Vector{Union{}}` with `undef`, and from then on the exception will be accessing `#undef` elements, not specifically having anything to do with `Union{}`. Eg

```julia
julia> a = Vector{Union{}}(undef, 4)
4-element Vector{Union{}}:
 #undef
 #undef
 #undef
 #undef

julia> a[2]
ERROR: UndefRefError: access to undefined reference

```

which would be the same error for ` Vector{Any}(undef, ...)` or any other abstract type.
