# How is it that new Julia programmers tend to abuse type annotations?

**URL:** <https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465>\
**Category:** Teaching & Outreach\
**Created:** [January 7, 2024, 1:40pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465 "2024-01-07T13:40:01Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [January 7, 2024, 6:08pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/21 "2024-01-07T18:08:25Z")

</div>

> [@joa-quim](#):
>
> > [@jkopper](#):
> >
> > I suppose I disagree that the behavior of the function g in your example is “bad.”
> 
> Agree.

Well yes, _when you know what you are doing_ then using a type restriction is in fact a nice feature, and you might have a lot of reasons to do that. But my concern is that people just throw type restrictions all around _assuming they would improve performance_, which they do not: I am not claiming that type restrictions themselves are bad, simply that this mistake tends to produce too many of them and induces later problems (like with the aforementioned ForwardDiff classic case).

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [January 7, 2024, 6:45pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/22 "2024-01-07T18:45:23Z")

</div>

Perhaps one actionable output of this process could be better documented guidance about when it makes sense to add type annotations in functions? Some additional ideas on top of what’s been mentioned already:

- For production (e.g. package) code, methods may want to constrain their type signatures if they’re unsure the functions they call can support arbitrary types. This is the `AbstractArray` case @mkitti mentioned.
- Conversely, methods should not over-constrain their types if they know all the functions they’ll call can support those types:

```julia
# unnecessary
square(a::Int) = a * a
square(a::Float32) = a * a
square(a::...) = a * a
...

# `*` is defined for all number types
square(a::Number) = a * a

```

- One challenge here is that not all types/functions have well-defined contracts around what operations/types they support. However, this is something we can work on as a community and has been talked about enough already that I’ll leave it at that.
- When one needs to check for some invariant that can’t be represented in the type system or would complicate dispatch, there’s nothing wrong with a dynamic check! Throwing an error early is better than letting one bubble up from deep within a method’s call stack at some unintelligible location. When dispatch is our hammer, many of us have been guilty of seeing everything as a nail. So while this point isn’t new, I see this lack of runtime error checking enough in the ecosystem that it bears repeating.

---

<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:** [January 7, 2024, 6:56pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/23 "2024-01-07T18:56:23Z")

</div>

> [@ToucheSir](#):
>
> ```julia
> # `*` is defined for all number types
> square(a::Number) = a * a
> 
> ```

That should just be `Any`. Strings, for example, support multiplication, too, and the square makes sense for them, too.

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [January 7, 2024, 6:58pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/24 "2024-01-07T18:58:36Z")

</div>

The last missing piece here may be that Julia works differently from many statically typed, compiled languages in that it’ll specialize on types as it encounters them at call sites, rather than what is declared in a method definition. One analogy with C++ is that ([almost](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing)) all arguments in Julia functions are [`auto`](https://en.cppreference.com/w/cpp/language/function_template#Abbreviated_function_template), which means they can be specialized upon without specifying explicit concrete types.

[Methods · The Julia Language](https://docs.julialang.org/en/v1/manual/methods/#man-method-specializations) in the manual talks about this briefly, but one loose heuristic I found helps is to insert implicit type parameters in your head. Thus, this

```julia
f(a, b::AbsType, c) = ...

```

Would become

```julia
f(a::A, b::B, c::C) where {A, B <: AbsType, C} = ...

```

And it’s much clearer why the compiler could specialize for different combinations of A, B and C despite the definition of `f` not providing any concrete type bounds for them. It’s a heuristic because the compiler may choose to not specialize on them, but that can also apply for arguments with provided types.

---

<div class="post-metadata">

**Author:** ![ToucheSir](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/touchesir/32/14411_2.png) [@ToucheSir](https://discourse.julialang.org/u/ToucheSir)\
**Post date:** [January 7, 2024, 7:01pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/25 "2024-01-07T19:01:18Z")

</div>

I hope it was clear that this is a purely illustrative example.

---

<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:** [January 7, 2024, 7:06pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/26 "2024-01-07T19:06:10Z")

</div>

> [@ToucheSir](#):
>
> better documented guidance about when it makes sense to add type annotations in functions

IMO:

1. Use type assertions (on an expression within a function body) abundantly, whenever it makes sense. When calling another function, say `f`, it often makes sense to assert that the obtained value is of correct type: `f(arg)::T`.

2. Try not to use type annotations when declaring local variables.

3. The dispatch/method case is much more nuanced and trickier. Some notes:

---

<div class="post-metadata">

**Author:** ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)\
**Post date:** [January 7, 2024, 7:41pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/27 "2024-01-07T19:41:23Z")

</div>

> [@ToucheSir](#):
>
> Perhaps one actionable output of this process could be better documented guidance about when it makes sense to add type annotations in functions?

It could be a good feature for the language server.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [January 7, 2024, 9:46pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/28 "2024-01-07T21:46:10Z")

</div>

> [@ToucheSir](#):
>
> Perhaps one actionable output of this process could be better documented guidance about when it makes sense to add type annotations in functions?

How about the [Argument-type declarations](https://docs.julialang.org/en/v1/manual/functions/#Argument-type-declarations) section of the manual, which was written specifically to provide such guidance? What improvements would you suggest?

---

<div class="post-metadata">

**Author:** ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)\
**Post date:** [January 7, 2024, 10:50pm UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/29 "2024-01-07T22:50:26Z")

</div>

> [@stevengj](#):
>
> What improvements would you suggest?

Would it be possible to put this text inside a box like the text about Shared memory between arguments?

> In general, you should use the most general applicable abstract types for arguments, and **when in doubt, omit the argument types**. You can always add argument-type specifications later if they become necessary, and you don’t sacrifice performance or functionality by omitting them.

I believe that this type of practical aspects should be highlighted more.

---

<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:** [January 8, 2024, 1:19am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/30 "2024-01-08T01:19:58Z")

</div>

> [@joa-quim](#):
>
> I think I brought this some years ago but it still can’t get it why `string(something)` is not guarantied to return a `String` (and same for `FloatXX(...)` and others.).

Those are specific cases that make sense but the general cases don’t.

- `string` is different from `FloatXX` because only the latter is a type, and a concrete one at that. Upper cased types have associated lower cased functions that are not desired to always return the type. An API-compliant `string` method could sensibly return other subtypes of `AbstractString`. It could be even less restricted like `Iterators.reverse`. Generally, `Reverse(Reverse(x))` wraps doubly, but `reverse(reverse(x))` sensibly unwraps to `x`.
- People definitely want concrete type constructors to only return that concrete type or error; the varying return types are relegated to the lower cased functions. However, there’s no 1 concrete return type for abstract type constructors, including iterated unions like `Complex`. Guaranteeing that `AbstractFloat` returns an `AbstractFloat` doesn’t help much.

At best we might want return types for type constructors, though it’d only narrow down enough for concrete ones like `Complex{Int}`, and maybe we can have a manual option for arbitrary callables, not sure if `function foo::String end` is a proper appropriation or sufficiently restricted to concrete types (or perhaps small Unions).

It’s also worth pointing out that this is at best an attempted type conversion and an assertion of the return type in subsequent code. This won’t eliminate the runtime dispatch of the call, and you can’t catch a failed `convert` in infinite call signatures ahead of time. Statically typed languages restrict polymorphism to pull this off.

> [@nsajko](#):
>
> Strings, for example, support multiplication, too

Concatenation, not multiplication, they just share an operator. It doesn’t make much sense to say a string can be “squared,” even if the underlying operator works.

---

<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:** [January 8, 2024, 7:26am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/31 "2024-01-08T07:26:52Z")

</div>

Another important consideration is invalidations.

Let’s try the untyped version first. We get invaldations. Recompilation will be forced.

```julia-repl
julia> f(x) = x
f (generic function with 1 method)

julia> function g(v)
           s = 0
           for e in v
               s += f(e)
           end
           return s
       end
g (generic function with 1 method)

julia> g(Number[5,3,2,1])
11

julia> using SnoopCompile, AbstractTrees # Use SnoopCompileCore in a real scenario

julia> invalidations = @snoopr begin
           f(::Float64) = 2.0
       end
6-element Vector{Any}:
  MethodInstance for g(::Vector{Number})
 1
  MethodInstance for f(::Number)
  "jl_method_table_insert"
  f(::Float64) @ Main REPL[5]:2
  "jl_method_table_insert"

julia> trees = invalidation_trees(invalidations)
1-element Vector{SnoopCompile.MethodInvalidations}:
 inserting f(::Float64) @ Main REPL[5]:2 invalidated:
   backedges: 1: superseding f(x) @ Main REPL[1]:1 with MethodInstance for f(::Number) (1 children)

julia> print_tree(trees[1].backedges)
InstanceNode[MethodInstance for f(::Number) at depth 0 with 1 children]
└─ MethodInstance for f(::Number) at depth 0 with 1 children
   └─ MethodInstance for g(::Vector{Number}) at depth 1 with 0 children

```

Now let’s try a typed version. No invalidations, no recompilation!

```julia-repl
julia> f(x::Int) = x
f (generic function with 1 method)

julia> function g(v)
           v2::Vector{Int} = v
           s = 0
           for e in v2
               s += f(e)
           end
           return s
       end
g (generic function with 1 method)

julia> g(Number[5,3,2,1])
11

julia> using SnoopCompile

julia> invalidations = @snoopr begin
           f(::Float64) = 2.0
       end
Any[] # no invalidations, no recompilation!

```

---

<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:** [January 8, 2024, 9:05am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/32 "2024-01-08T09:05:26Z")

</div>

> [@mkitti](#):
>
> ```julia
> function g(v)
> v2::Vector{Int} = v
> 
> ```

Though if it was important to restrict the iterable to a `Vector{Int}`, it’d be more practical to restrict the method to `g(v::Vector{Int})` and do the `eltype` conversion separately. After all, `Number` elements can’t all be converted to `Int`, so the second version is more prone to runtime errors in exchange for resistance to invalidations, broadly speaking it is less flexible.

---

<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:** [January 8, 2024, 10:39am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/33 "2024-01-08T10:39:19Z")

</div>

> [@nsajko](#):
>
> Probably you’re using some package (possibly indirectly), that defines an (imperfect) method for `Base.string`. Hard to tell without more information, but I can tell you this: when starting a fresh Julia REPL, for all of Julia v1.9, v1.10 and nightly (future v1.11), all methods infer as either `String` or `AbstractString`. This is the command: `Base.return_types(string, Tuple{Any})` (the entries correspond to the output of `methods`).

Relevant PR: [improve return type inference for `string` by nsajko · Pull Request #52806 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/52806)

Relevant Discourse topic (potential Julia bug?): [Why is `Base.return_types(String, Tuple{AbstractVector{UInt8}})` so pessimistic for this method?](https://discourse.julialang.org/t/why-is-base-return-types-string-tuple-abstractvector-uint8-so-pessimistic-for-this-method/108505)

@joa-quim @Benny

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [January 9, 2024, 3:37am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/34 "2024-01-09T03:37:05Z")

</div>

FWIW, when I’m creating code for work – not library development – I type-annotate almost every argument in my methods where it is feasible. I strongly prefer method errors that tell me the expected and actual types at the level of my code to more cryptic errors further down the call stack.

I mention this because, when I first started using Julia, I read that I “shouldn’t over annotate” and took that at face value. I think there are plenty of good reasons to reduce the generality of your code. Just not if you are trying to share it with others.

---

<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:** [January 9, 2024, 4:53am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/35 "2024-01-09T04:53:33Z")

</div>

Yeah the problem with “don’t over-annotate” is it doesn’t quite get across where the lines are. If you need your method, or even the whole function, to only be dispatched on particular argument types, annotating is the appropriate measure. The tip is intended to inform people that restricting dispatch with argument annotations often doesn’t help the compiler optimize a call. Specifying types for fields, parameters, variables, or right-hand expressions actually do things that help (or hurt) compiler optimizations. It’s probably fair that 1 tip is no substitute for learning the language, but it’s also probably possible to make a beginner’s tutorial that lays out how types are communicated to the compiler in one smaller place. Toy example code in articles intended for highlights rather than teaching tends to leave out annotations entirely, which really misleads people into thinking Julia is alternate Python.

---

<div class="post-metadata">

**Author:** ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)\
**Post date:** [January 9, 2024, 9:10am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/36 "2024-01-09T09:10:39Z")

</div>

> [@Benny](#):
>
> it’s also probably possible to make a beginner’s tutorial that lays out how types are communicated to the compiler in one smaller place.

That would be a fantastic idea. I think Julia uses types in such a unique way that it takes some time to get used to them. Type annotations in other programming languages are mandatory or useful, but never detrimental as they can be in Julia. In the future, there might even be exercises similar to these Python type exercises.

> **[Python Type Challenges - Learn & Master Type Hints](https://python-type-challenges.zeabur.app)**
>
> Learn Python typing (type hints) with interactive online exercises!

---

<div class="post-metadata">

**Author:** ![fer2tdt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fer2tdt/32/47427_2.png) [@fer2tdt](https://discourse.julialang.org/u/fer2tdt)\
**Post date:** [January 9, 2024, 9:38am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/37 "2024-01-09T09:38:45Z")

</div>

> [@lrnv](#):
>
> type annotations on parameters on function

0.- Morning. After a year learning and working with “Julia” every day, I continue being a “newcommer”… at this time, and I am afraid that some years more…

Like a “newcommer” I wonder…

Q1.- Could be that we are thinking that we have better performance by explicit “type annotations on parameters on function” because we can find this expresion:

_“The Julia compiler is able to generate efficient code in the presence of `Union` types with a small number of types [[1]](https://docs.julialang.org/en/v1/manual/types/#footnote-1), by generating specialized code in separate branches for each possible type.”_

[Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#Type-Unions)

Q2.- Could be that in many situations we need to be sure about what Types Julia is using in all operations into the function. Because allways we need to be certain of the results of the calculations.

An easy example:

```julia
a=123456789123
println("es ",a, " y T d a = ", typeof(a))
r2=a*a
println("es ",r2, " y T d a*a = ",typeof(r2))
r3=a*a*a
println("es ",r3, " y T d a*a*a = ", typeof(r3))
r4=a*a*a*a
println("es ",r4, " y T d a*a*a*a = ", typeof(r4))

```

The result here is an (error by) overflow ( in fact without any notice ) because Julia continue using the same “default type”.

```julia
es 123456789123 y T d a = Int64
es 4568175676801474313 y T d a*a = Int64
es -8268922784655733861 y T d a*a*a = Int64
es -8138388883848516015 y T d a*a*a*a = Int64

```

Assertion.- You should be careful with the recommendations because you do not know all the calculation scenarios in which we are working. We may be “newcomers” in Julia but not in the details of Scientific Calculus.

Thanks anyway.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [January 9, 2024, 9:48am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/38 "2024-01-09T09:48:31Z")

</div>

I appologise if the “newcommer” tag offended you, I was including myself in it by the way.

Once again, I do not assume people are stupid, and I agree that type assertions _are a useful part of the language_, I was just noting that people tend to use them with wrong assumption about what they will do, people that i tagged “newcommers”, maybe a bit quickly indeed.

> [@fer2tdt](#):
>
> Q1.- Could be that we are thinking that we have better performance by explicit “type annotations on parameters on function” because we can find this expresion:
> 
> _“The Julia compiler is able to generate efficient code in the presence of `Union` types with a small number of types [[1]](https://docs.julialang.org/en/v1/manual/types/#footnote-1), by generating specialized code in separate branches for each possible type.”_
> 
> [Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#Type-Unions)

I think this sentence is referring to the ability of Julia to split unions, which has nothing to do with what we are talking about here – There is indeed a potential for confusion there, maybe we could fix the docs.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [January 9, 2024, 10:47am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/39 "2024-01-09T10:47:08Z")

</div>

I think the thing with type assertions is mostly just that it’s a bit of a [Pascal’s wager](https://en.wikipedia.org/wiki/Pascal's_wager) but for performance. Someone who is new to the language often knows that types are an important part of how julia is able to be fast, and they’ll also know that there are _certain circumstances_ (e.g. structs or type instabilities) where a type annotation can have a large beneficial performance impact.

Hence, if the user doesn’t know precisely what circumstances the type annotations help, and what circumstances it’s superfluous, it’s pretty natural to just respond with “well, I’ll just put type annotations everywhere, it’s not that hard to do and maybe it’ll speed things up”.

---

<div class="post-metadata">

**Author:** ![xiaoxi](https://avatars.discourse-cdn.com/v4/letter/x/a9adbd/32.png) [@xiaoxi](https://discourse.julialang.org/u/xiaoxi)\
**Post date:** [January 9, 2024, 11:49am UTC](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465/40 "2024-01-09T11:49:35Z")

</div>

Don’t the latest developments in Cthulhu.jl and its integration into the VS Code extension solve most of the problems newcomers face with Julia types?

> <https://github.com/JuliaDebug/Cthulhu.jl/pull/469>
>
> Depends on https://github.com/julia-vscode/julia-vscode/pull/3328 for showing ty…pes inline, however can be merged in before.
> 
> This pr show types in the source code when using the repl in VSCode, e.g. \`@descend f(1)\` with warnings on gives
> !\[image\](https://github.com/JuliaDebug/Cthulhu.jl/assets/19725290/77fd3e0a-7554-46ab-98d1-2ec3593b3e9e)
> And without warnings 
> !\[image\](https://github.com/JuliaDebug/Cthulhu.jl/assets/19725290/dd12a9a5-6dc1-4cf1-8ccb-0638a96db7fa)
> 
> There a couple improvements I still want to make to this pr: 
> 
> \- \[x\] Adding a way to toggle the vscode integration (should this be implemented the same way the warn toggle works?)
> \- \[x\] Removing the duplication of tests in TypedSyntax (I tried putting the tests into a separate file and using \`include\` but then the \`m = @which TSN.unnamedargs(Matrix{Float32}, Int; a="hello")\` test started failing claiming \`mi\` was \`nothing\`) 
> \- \[x\] Adding a way to automatically show types in VSCode for any called functions in an open file without having to descend into them.
> 
> As an example of how to change the colour of the hints in VSCode, I'm using the Monokai theme with the following in my \`settings.json\`
> \`\`\`json
> "workbench.colorCustomizations": {
> // Name of the theme you are currently using
> "\[Monokai\]": {
> // Overrides for specific kinds of inlay hints
> "editorInlayHint.typeForeground": "#66D9EF",
> "editorInlayHint.typeBackground": "#00000000",
> "editorInlayHint.parameterForeground": "#f8f8f2", // defaults from https://github.com/microsoft/vscode/blob/2e335d2df2001439b09483e7fcff8379ac1a7a16/extensions/theme-monokai/themes/monokai-color-theme.json#L41-L42
> "editorInlayHint.parameterBackground": "#75715E",
> // Colours for unstable types when warnings are on
> "editorInlayHint.foreground": "#e13030",
> "editorInlayHint.background": "#00000000",
> }
> }
> \`\`\`

[Previous page](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465.md?page=1)

[Next page](https://discourse.julialang.org/t/how-is-it-that-new-julia-programmers-tend-to-abuse-type-annotations/108465.md?page=3)
