# On type annotations

**URL:** https://discourse.julialang.org/t/on-type-annotations/116305
**Category:** New to Julia
**Created:** [June 27, 2024, 1:13pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305 "2024-06-27T13:13:24Z")
**Posts on this page:** 20
**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: [June 27, 2024, 1:13pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/1 "2024-06-27T13:13:24Z")

</div>

I wonder if there are any risks or issues with type annotations. In short, together with colleagues I am writing a coding standard. All Julia code at my company must be implemented following this standard. Some packages contain hundreds of structs. So it seems that annotating functions and variables is a good idea for readability and maintainability of code. The annotation guarantees that the variable will not change type as long as it lives. The type annotation of functions guarantees the return type. Both types of annotations improve maintainability and readability of the code. I know that under some circumstances `convert` is called. We intend to use static code checking techniques to make sure that functions are variables are type annotated, so there will be no escaping of annotations for developers.

Of course, type annotations of arguments of functions reduce re-usability of such a function for other types, but that does not concern us.

To be explicit, we have in mind to type annotate functions, function arguments and variables like so:

```julia
function f(value::Float64, obj::MyStruct)::OtherStruct
    vec::Vector{Float64} = [1.0, 2.0, 3.0]
    other::OtherStruct = calculate_other_struct(value, obj, vec)
    return other
end

```

If the type annotation is hard-coded as the inferred type, we can’t imagine there is any problem. Is there something we miss?

---

<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: [June 27, 2024, 1:21pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/2 "2024-06-27T13:21:08Z")

</div>

> [@Matthijs\_1971](#):
>
> The annotation guarantees that the variable will not change type as long as it lives.

Not sure whether this is an issue for you or you’re referring to something else but just to be sure:

```julia
julia> function f(value::Float64)
           vec::Vector{Float64} = [1.0, 2.0, 3.0]
           vec = Int32.(vec)
       end

f (generic function with 1 method)

julia> f(1.0)
3-element Vector{Int32}:
 1
 2
 3

```

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [June 27, 2024, 1:26pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/3 "2024-06-27T13:26:14Z")

</div>

> [@Matthijs\_1971](#):
>
> Of course, type annotations of arguments of functions reduce re-usability of such a function for other types, but that does not concern us.

Are you sure? If you make input types Float64 you cannot use automated differentiation any longer (for which you need dual numbers) which comes in handy when you do machine learning or optimizations, for example.

And if you have vec::Vector{Float64} you cannot pass an SVector any longer. But an SVector is much faster for small vectors…

---

<div class="post-metadata">

### Author: ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)
#### Post date: [June 27, 2024, 1:28pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/4 "2024-06-27T13:28:12Z")

</div>

> [@nilshg](#):
>
> ```julia
> julia> function f(value::Float64)
> vec::Vector{Float64} = [1.0, 2.0, 3.0]
> vec = Int32.(vec)
> end
> 
> f (generic function with 1 method)
> 
> julia> f(1.0)
> 3-element Vector{Int32}:
> 
> ```

You are not observing the type of `vec` there but returning the value of the right hand side of the last assignment.

---

<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: [June 27, 2024, 1:56pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/5 "2024-06-27T13:56:38Z")

</div>

Ah of course, thank you. To correct:

```julia
julia> function g(value::Float64)
           vec::Vector{Float64} = [1.0, 2.0, 3.0]
           vec = ["a", "b", "c"]
           return vec
       end
g (generic function with 1 method)

julia> g(1.0)
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64

```

---

<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: [June 27, 2024, 1:58pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/6 "2024-06-27T13:58:51Z")

</div>

> [@nilshg](#):
>
> ```julia
> function f(value::Float64)
> vec::Vector{Float64} = [1.0, 2.0, 3.0]
> vec = Int32.(vec)
> end
> 
> ```

The return type must be annotated too in the function signature. What I did not mention in the question, is that a return statement with a variable will also be mandatory. So the function would be implemented according to the standard like so:

```julia
function f(value::Float64)::Vector{Float64}
           vec::Vector{Float64} = [1.0, 2.0, 3.0]
           vec = Int32.(vec)
           println(typeof(vec), vec)
           return vec
end

r = f(2.0) # Annotation intentionally omitted for evaluation
println(typeof(r), r)

```

with output

```julia
Vector{Float64}[1.0, 2.0, 3.0]
Vector{Float64}[1.0, 2.0, 3.0]

```

---

<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: [June 27, 2024, 2:02pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/7 "2024-06-27T14:02:39Z")

</div>

IMHO, the annotations for the input/output of the functions are ok. They reduce flexibility, but are actually useful for finding errors.

~~The annotations \*inside\* the functions I don't find appealing. Something like:

```julia
  vec::Vector{Float64} = [1.0, 2.0, 3.0]

```

 ~~

~~only guarantees that one doesn’t assign to `vec`, **at that line** something that is not a vector of `Float64`. But doesn’t provide any guarantee about what `vec` will be inside the function, and just adds a lot of boilerplate.~~

(to increase the utility of type annotations of function input and output, of course, try to use the smallest functions possible)

---

<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: [June 27, 2024, 2:04pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/8 "2024-06-27T14:04:57Z")

</div>

We will not be writing code for the community or so, so re-usability is probably not such an issue. Our data structures (and structs) tend to be rather larger than I have seen elsewhere in my career.

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [June 27, 2024, 2:06pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/9 "2024-06-27T14:06:57Z")

</div>

> [@Matthijs\_1971](#):
>
> re-usability is probably not such an issue

Are you sure you never want to use your functions in the context of an optimization algorithm? Never with distributions because you never have to determine error margins?

---

<div class="post-metadata">

### Author: ![era127](https://avatars.discourse-cdn.com/v4/letter/e/eb8c5e/32.png) [@era127](https://discourse.julialang.org/u/era127)
#### Post date: [June 27, 2024, 2:07pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/10 "2024-06-27T14:07:42Z")

</div>

You could use the type assert in the return line too if you want to explicitly check without the convert, and I think jet will still pick up the type when checking the code. There is an old thread that looks at the performance impact of the type assert. Like this:

`return other::OtherStruct`

---

<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: [June 27, 2024, 2:09pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/11 "2024-06-27T14:09:19Z")

</div>

> [@nilshg](#):
>
> `vec = ["a", "b", "c"]`

This looks what we want to prevent indeed. Such type changes make it very hard to reason about code in lengthy functions.

---

<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: [June 27, 2024, 2:09pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/12 "2024-06-27T14:09:53Z")

</div>

There is a simpler usability issue with annotating with `Vector{Float64}`, which is the impossibility of passing slices:

```julia-repl
julia> f(x::Vector{Float64}) = x
f (generic function with 1 method)

julia> x = rand(3);

julia> f(@view(x[1:2]))
ERROR: MethodError: no method matching f(::SubArray{Float64, 1, Vector{Float64}, Tuple{UnitRange{Int64}}, true})

```

(that can be solved using `AbstractVector{Float64}` - which also solves the possible uses of StaticArrays).

---

<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: [June 27, 2024, 2:14pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/13 "2024-06-27T14:14:23Z")

</div>

I don’t follow. I think the annotation makes sure that `vec` remains of type `Vector{Float64}` until garbage collected. Can specify your posting with a code snippet?

---

<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: [June 27, 2024, 2:23pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/14 "2024-06-27T14:23:40Z")

</div>

Sorry, you’re right (I confused it with the global scope, where the annotation is just a conversion at the typed line). Another pattern that might be interesting is to use `local`, to not mix annotations with assignments.

```julia
julia> function f()
           local y::Vector{Float64}
           y = [1.0, 2.0]
           return y
       end

```

---

<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: [June 27, 2024, 2:51pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/15 "2024-06-27T14:51:53Z")

</div>

> [@Matthijs\_1971](#):
>
> `vec::Vector{Float64} = [1.0, 2.0, 3.0]`

This sort of annotation I would advise against. It is redundant and non-idiomatic, essentially line-noise, at worst causing performance loss or bugs.

If you want to assert a type like this, do it on the right hand side

```julia
vec = foo()::Vector{Float64}

```

Also, it just seems lik bad taste, imo, to use a type assertion on a literal value that is guaranteed by definition to produce the correct type, like eg.

```julia
str::String = "hello" 

```

---

<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: [June 27, 2024, 2:56pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/16 "2024-06-27T14:56:10Z")

</div>

Our company is large, so I can never say never. What specific functionality or package did you have in mind that will be blocked by the type annotations?

---

<div class="post-metadata">

### Author: ![ufechner7](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ufechner7/32/51363_2.png) [@ufechner7](https://discourse.julialang.org/u/ufechner7)
#### Post date: [June 27, 2024, 3:02pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/17 "2024-06-27T15:02:19Z")

</div>

Any optimizer that uses automatic differentiation, e.g. [Introduction · JuMP](https://jump.dev/JuMP.jl/stable/) , but many there are many more. Anyone who tries to use distributions, e.g. [Getting Started · Distributions.jl](https://juliastats.org/Distributions.jl/latest/starting/) . Anyone who tries to use physical units, e.g. [Home · Unitful.jl](https://painterqubits.github.io/Unitful.jl/stable/) .

---

<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: [June 27, 2024, 3:07pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/18 "2024-06-27T15:07:46Z")

</div>

> [@DNF](#):
>
> It is redundant

I just realized that it is not redudant:

```julia
julia> function f()
           y::Vector{Float64} = [1.0, 2.0]
           y = ["a", "b"]
           return y
       end
f (generic function with 1 method)

julia> f()
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64

julia> function g()
           y = [1.0, 2.0]
           y = ["a", "b"]
           return y
       end
g (generic function with 1 method)

julia> g()
2-element Vector{String}:
 "a"
 "b"

```

---

<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: [June 27, 2024, 3:14pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/19 "2024-06-27T15:14:30Z")

</div>

> [@lmiq](#):
>
> I just realized that it is not redudant:

Indeed, not redundant at all. It becomes very hard to write type unstable code too when all types are made explicit and like said, an annotated variable can not change type any more.

Can you specify the benefit of annotating on the right hand side of a function call? I guess this annotation will have to be repeated for any call to this function which seems to make the caller responsible for part of the contract between caller and callee. This becomes a bit complicated in nested calls, I think.

---

<div class="post-metadata">

### Author: ![stephancb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephancb/32/14243_2.png) [@stephancb](https://discourse.julialang.org/u/stephancb)
#### Post date: [June 27, 2024, 3:22pm UTC](https://discourse.julialang.org/t/on-type-annotations/116305/20 "2024-06-27T15:22:38Z")

</div>

> [@Matthijs\_1971](#):
>
> So it seems that annotating functions and variables is a good idea for readability and maintainability of code.

This is perhaps debatable, especially the “readability”. The option to omit cluttering type annotations is a feature of Julia, which is not available in other “performant” languages like C++. I would not remove it via a coding standard. The issue with type annotating everything arguably is readability.

More important is perhaps to invest in [testing](https://docs.julialang.org/en/v1/stdlib/Test/), especially checking whether `@inferred` types are ok. This would substitute annotating function types and in addition ensures efficient code, which is important in complex projects.

[Next page](https://discourse.julialang.org/t/on-type-annotations/116305.md?page=2)
