# Declaring Types in NamedTuples

**URL:** <https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [October 30, 2022, 12:05am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504 "2022-10-30T00:05:34Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 30, 2022, 12:05am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/1 "2022-10-30T00:05:34Z")

</div>

Julia 1.8 introduces new syntax to declare types of global variables…

```julia
julia> y::Int = 3
3

julia> y = 2.5
ERROR: InexactError: Int64(2.5)

julia> z::Number = π
π = 3.1415926535897...

julia> z = 1+1im
1 + 1im

julia> z = "Hello, world!"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Number

```

This syntax is consistent with method argument specification, for optional arguments:

```julia
g(x::Int=5) = x^2

```

I just learned that `NamedTuple`s can contain abstract types and be type-unstable just like `struct`s can, for example:

```julia
julia> x = NamedTuple{(:a, :b), Tuple{Number, Int}}((1, 2.0))
NamedTuple{(:a, :b), Tuple{Number, Int64}}((1, 2))

```

It would seem consistent that when constructing `NamedTuple`s, one should be able to declare the types using similar syntax, but:

```julia
julia> x = (a::Number=1, b::Int=2.0)
ERROR: syntax: invalid named tuple field name "a::Number" around REPL[42]:1

```

Any insights or opinions?

---

<div class="post-metadata">

**Author:** ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)\
**Post date:** [October 30, 2022, 4:10am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/2 "2022-10-30T04:10:16Z")

</div>

These are very different things that you are comparing, but yes, I suppose that you could have this syntax (probably we need to check for some edge case that is ambiguous) and it to be “Natural”. As you pointed out, however, there is a way to do it already that is just a little more verbose.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 30, 2022, 4:36am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/3 "2022-10-30T04:36:38Z")

</div>

Interestingly, the `Base.Pairs` that is generated by keyword arguments also support overriding concrete types with abstract types.

```julia
julia> x = NamedTuple{(:a, :b), Tuple{Number, Int}}((1, 2.0))
NamedTuple{(:a, :b), Tuple{Int64, Number}}((1, 2))

julia> ((; kwargs...)->kwargs)(; x...) |> typeof
Base.Pairs{Symbol, Number, Tuple{Symbol, Symbol}, NamedTuple{(:a, :b), Tuple{Number, Int64}}}

```

Strangely, however, while the regular `Tuple` supports changing concrete types, unlike `NamedTuple` it doesn’t support abstract types.

```julia
julia> y = Tuple{Number, Int, Float64}((1, 1.0, 1))
(1, 1, 1.0)

julia> typeof(y)
Tuple{Int64, Int64, Float64}

```

This inconsistency is vexxing.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [October 30, 2022, 6:38am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/4 "2022-10-30T06:38:48Z")

</div>

> [@uniment](#):
>
> This inconsistency is vexxing.

It’s because tuples are a very special type in Julia: they are covariant whereas all other types are invariant. This arises from their use to specify method signatures.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [October 30, 2022, 9:05am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/5 "2022-10-30T09:05:24Z")

</div>

Note that you can use typed globals with named tuples like this:

```julia
x::NamedTuple{(:a, :b), Tuple{Number, Int}} = (a=1, b=2.0)

```

or the shorter

```julia
x::@NamedTuple{a::Number, b::Int} = (a=1, b=2.0)

```

but I suppose that the syntax you propose (which is not about typed globals) could also be made to work…

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 30, 2022, 9:19pm UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/6 "2022-10-30T21:19:16Z")

</div>

It’s worth mention that `x::T=val` isn’t restricted to globals:

```julia
let x::Int = 5
    x = 6.5 # error
end

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 30, 2022, 9:31pm UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/7 "2022-10-30T21:31:03Z")

</div>

I would think `NamedTuple`s, which are invariant, are used for specifying keyword argument method signatures?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [October 31, 2022, 3:31am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/8 "2022-10-31T03:31:35Z")

</div>

The types of keyword arguments are not really part of method signatures, just the names:

```julia
julia> foo(; a::Int) = 1
foo (generic function with 1 method)

julia> foo(x::Int; b::Int) = 2
foo (generic function with 2 methods)

julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(; a) in Main at REPL[1]:1
[2] foo(x::Int64; b) in Main at REPL[2]:1

```

Most of the time I wouldn’t bother annotating the types of keyword arguments. The rule of thumb is argument annotations should only be used for dispatch, not for documentation or type safety. (And keyword arguments do not enter into dispatch.)

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 31, 2022, 4:49am UTC](https://discourse.julialang.org/t/declaring-types-in-namedtuples/89504/9 "2022-10-31T04:49:31Z")

</div>

And yet the keyword argument types are respected, despite their types not being reported by `methods`:

```julia
julia> foo(; a::Number=1) = a
foo (generic function with 1 method)

julia> methods(foo)
# 1 method for generic function "foo":
[1] foo(; a) in Main at REPL[1]:1

julia> foo()
1

julia> foo(a=π)
π = 3.1415926535897...

julia> foo(a=1+1im)
1 + 1im

julia> foo(a="Hello, world!")
ERROR: TypeError: in keyword argument a, expected Number, got a value of type String

```

However methods that _specialize_ on keyword arguments (by overloading keyword arguments) is disallowed.
