# The runtime type and the variable type

**URL:** <https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868>\
**Category:** New to Julia\
**Created:** [October 28, 2024, 12:06pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868 "2024-10-28T12:06:56Z")\
**Posts on this page:** 18\
**Page:** 1

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 28, 2024, 12:06pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/1 "2024-10-28T12:06:56Z")

</div>

Here’s a short experiment which demonstrates that the runtime type is an independent piece of information from the type of a variable.

```julia
julia> x::Any="hello world"
"hello world"

julia> typeof(x)
String

julia> x=1
1

julia> typeof(x)
Int64

```

In the example above, the type of the variable `x` is `Any`, but the type of the _data in memory which_ `x` _refers to_ is _either_ `String` _or_ `Int64` depending on the _concrete type of the data in memory_.

```julia
julia> x::String="hello world"
"hello world"

julia> typeof(x)
String

julia> x=1
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type String
The function `convert` exists, but no method is defined for this combination of argument types.

```

In this example, `x` is constrained and therefore the variable `x` cannot refer to data in memory of type `Int64`.

Is there a way to retrieve or query the type of the variable `x` itself, rather than the type of the data which `x` references?

In other words, a function `f` such that

- `f(x) -> Any` in the first example
- `f(x) -> String` in the second example

Sorry if the answer to this question is obvious or mentioned somewhere in the docs. If it is, I missed it.

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [October 28, 2024, 12:26pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/2 "2024-10-28T12:26:27Z")

</div>

There might be two misunderstandings at play here:

First, variables don’t have types in Julia, only values do. In your first example, the variable `x` does not have a type in itself. The value is a `String` and therefore `x` is bound to a value of type `String`.

In the code `x::Any="hello world"`, the `x::Any` part means that in the given scope, the variable `x` may only be bound to values of type `Any`. Again, the variable itself has no type independent from the value

The second issue is that since `Any` is a supertype of `String` and `Int`, all instances of the two latter types are also instances of `Any`. So the two statements “`x` is an instance of `Any`” and “`x` is an instance of `String`” are not mutually exclusive.

Therefore, the function `f` you are looking for cannot exist. In both your cases, the type of the value `x` is `String` AND `Any`. This is analogous to how I am both a human, a mammal, a vertebrate, an animal and an organism.

There is a related question which is similar to, but not quite the same as the question you are asking. You could ask “what type has the compiler inferred that the type of `x` is?”. Note that the difference between this question and the above is that the compiler could infer only that the type is `Any`, whereas the type could be `String`. The compiler only needs to infer a supertype of the concrete type - it does not have to infer the concrete type of the value.  
Semantically, there is no difference whether the compiler infers `Any`, or `Union{Int, Char, String}`, or `String` - the code will behave the same. However, the generated code will be more efficient if it infers a concrete type.  
And there is currently no supported, stable way of programmatically getting the inferred type of a value.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [October 28, 2024, 12:38pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/3 "2024-10-28T12:38:36Z")

</div>

@jakobnissen’s point notwithstanding, there is a function `Core.get_binding_type` which, similarly to `fieldtype`, returns the type of a binding in a given module. In your example, `Core.get_binding_type(@ __MODULE__ , :x)` would get you the type of the binding `x` in the current module. Note however how you need to specify both the module where the binding lives and the name of the binding.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [October 28, 2024, 1:29pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/4 "2024-10-28T13:29:53Z")

</div>

To elaborate on jakobnissens description. Variables in julia should not be thought of as a particular memory location or register with a particular size, like in C, rust or similar. A variable is just a name. The name might reference a value. The value has a type. Only values have types, and the type of a value is always concrete. Variables are just names. The syntax `myvar::Int = 0` constrains `myvar` to only reference values of type `Int`, but the variable `myvar` still has no type, the value it references has a type.

When assigning to variables with such a declared type, the right hand side will implicitly be converted to the declared type. If that can’t be done, an error will be thrown. Unlike other dynamical languages, there is usually no performance to gain by declaring a type for a variable. (Unless the variable is global).

```julia
julia> c::Int = 0
julia> c = 2.0
julia> c = 2.5
ERROR: InexactError: Int64(2.5)
Stacktrace:
...

```

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 29, 2024, 12:10pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/5 "2024-10-29T12:10:36Z")

</div>

> [@jakobnissen](#):
>
> First, variables don’t have types in Julia, only values do. In your first example, the variable `x` does not have a type in itself.

The reason why I think variables themselves must have type information associated with them is without this (runtime) type information, there would be no way for `x` to reject the assignment of a value of the _wrong_ type to itself.

It is quite likely that my mental model for where this data lives is wrong.

At runtime, there must be two (three) pieces of information.

- The type information which states what type `x` has right now
- The type information which states what the set of possible types which can be assigned to `x` are
- (The data, or value, assigned to `x`)

For example

```julia
x::Any = "Hello World"

```

- Right now, the type of `x` is `String`
- But, we can change it: `x = 1`. There must be a way at runtime for Julia to know this is permissible, surely?
- (The value is `"Hello World"`, which has the type of `String`)

Possibly I’m wrong and misunderstand the internal workings of the typesystem. (Quite likely.) But, without this additional piece of information, how can Julia know, at runtime, whether assignment of another type to an existing variable is permitted.

Actually, it could be that I have answered my own question.

- If the type information is gone by the time the JIT process is completed, then this may explain the solution. _However,_ elsewhere in the docs I saw some code/pseudocode which showed that Julia variables at runtime are represented in a very similar way to Python. Maybe I misunderstood something here.
- See: [Memory layout of Julia Objects · The Julia Language](https://docs.julialang.org/en/v1/devdocs/object/)

> [@simeonschaub](#):
>
> there is a function `Core.get_binding_type` which, similarly to `fieldtype`, returns the type of a binding in a given module. In your example, `Core.get_binding_type(@ __MODULE__ , :x)` would get you the type of the binding `x` in the current module.

This might be related to the above?

> [@sgaure](#):
>
> The syntax `myvar::Int = 0` constrains `myvar` to only reference values of type `Int`, but the variable `myvar` still has no type, the value it references has a type.

Yes - I think you summarized it more clearly than I have. My question, in part, is what mechanism provides this? How does it work?

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [October 29, 2024, 12:23pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/6 "2024-10-29T12:23:01Z")

</div>

Yeah you are basically right. However, Julia doesn’t provide any way of programmatically getting the “assigned type of a variable”, e.g. `Any` in the example `x::Any = "Hello World"`.

Or rather, the function `Core.get_binding_type` will do that, but this is an internal function, and may be removed or change behaviour in future versions of Julia. It is essentially part of the compiler/runtime internals.  
At the level of the exposed, public Julia semantics (as opposed to the compiler internals), only values and their types exist.

In a similar vein, for a certain functions, the compiler may completely optimise the existence of runtime types away. However, from the viewpoint of Julia semantics, the types are always present even if any particular generated piece of code may have optimised it away.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [October 29, 2024, 12:27pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/7 "2024-10-29T12:27:14Z")

</div>

> [@world-peace](#):
>
> or example
> 
> ```julia
> x::Any = "Hello World"
> 
> ```
> 
> - Right now, the type of `x` is `String`
> - But, we can change it: `x = 1`. There must be a way at runtime for Julia to know this is permissible, surely?

No. It’s mostly a compile time thing. Or, to take an example. Say you do

```julia
x::String = "hello"
x = 1

```

If the variable `x` has a declared type `T`, every assignment `x = a` will be lowered to `x = convert(T, a)`. The `convert` function is almost always inlined, and if the program is written properly, the type of `a` can be inferred by the compiler, and the `convert` does not need any runtime information, but may emit a single instruction e.g. converting from integer to float.

If the types of variables can not be inferred, i.e. the code is not type stable, there will be a lot of type checks, as you suggest. Performant code should be type stable, i.e. in every function, the types of every variable can be inferred from the types of the input variables.

```julia
julia> f() = (x::String="hello"; x = 1)
f (generic function with 1 method)

julia> @code_lowered f()
CodeInfo(
1 ─ Core.NewvarNode(:(x))
│ @_3 = "hello"
│ %3 = @_3
│ %4 = %3 isa Main.String
└── goto #3 if not %4
2 ─ goto #4
3 ─ %7 = @_3
│ %8 = Base.convert(Main.String, %7)
│ %9 = Main.String
└── @_3 = Core.typeassert(%8, %9)
4 ┄ %11 = @_3
│ x = %11
│ @_4 = 1
│ %14 = @_4
│ %15 = %14 isa Main.String
└── goto #6 if not %15
5 ─ goto #7
6 ─ %18 = @_4
│ %19 = Base.convert(Main.String, %18)
│ %20 = Main.String
└── @_4 = Core.typeassert(%19, %20)
7 ┄ %22 = @_4
│ x = %22
└── return 1
)

```

And, then:

```julia
julia> @code_typed f()
CodeInfo(
1 ─ nothing::Nothing
│ nothing::Nothing
│ nothing::Nothing
│ Base.convert(Main.String, 1)::Union{}
└── unreachable
) => Union{}

```

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 29, 2024, 12:50pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/8 "2024-10-29T12:50:26Z")

</div>

> [@jakobnissen](#):
>
> Or rather, the function `Core.get_binding_type` will do that, but this is an internal function, and may be removed or change behaviour in future versions of Julia. It is essentially part of the compiler/runtime internals.  
> At the level of the exposed, public Julia semantics (as opposed to the compiler internals), only values and their types exist.

Thanks - very useful to know about this.

> [@sgaure](#):
>
> If the variable `x` has a declared type `T`, every assignment `x = a` will be lowered to `x = convert(T, a)`.

Ah, so this explains it. The compiler knows the “target type” and it knows the target type differs from the source type, so it will insert calls to `convert(targetType, referenceToSourceData)`

> [@sgaure](#):
>
> If the types of variables can not be inferred, i.e. the code is not type stable, there will be a lot of type checks, as you suggest. Performant code should be type stable, i.e. in every function, the types of every variable can be inferred from the types of the input variables.

This is potentially more interesting.

If a function is written, and somewhere in that function it uses some global value as input, then the compiler cannot (might not) know what type that global value has.

```julia
function anon(x::Int64)
    y::Union{Int64, String} = globalVariable
    if y isa String
        return x + 1
    else
        return x + 2
    end
end

```

I think the interesting line here is

`y::Union{Int64, String} = globalVariable`

where `globalVariable::Any`.

What does the compiler have to do here? At runtime, `globalVariable` can have any type, and it could be converted to one of two types. So it doesn’t look like a simple call to `convert(Union{Int64, String}, globalVariable)` can be inserted here… Or can it?

---

<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:** [October 29, 2024, 12:58pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/9 "2024-10-29T12:58:02Z")

</div>

> [@world-peace](#):
>
> `y::Union{Int64, String} = globalVariable`
> 
> where `globalVariable::Any`.
> 
> What does the compiler have to do here? At runtime, `globalVariable` can have any type, and it could be converted to one of two types. So it doesn’t look like a simple call to `convert(Union{Int64, String}, globalVariable)` can be inserted here… Or can it?

`globalVariable` can have any type, but `y` still has a finite union type, and it won’t be re-bound if `globalVariable` is re-bound.

This is very easy to check:

```julia
julia> glob = 1;

julia> y::Union{Int, String} = glob;

julia> glob = [1,2,3];

julia> y
1

julia> glob
3-element Vector{Int64}:
 1
 2
 3

```

This means that a function referencing `y` always knows it’ll get `Int` or `String`, whereas referencing `glob`, it doesn’t know anything.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [October 29, 2024, 12:59pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/10 "2024-10-29T12:59:45Z")

</div>

> [@world-peace](#):
>
> What does the compiler have to do here? At runtime, `globalVariable` can have any type, and it could be converted to one of two types. So it doesn’t look like a simple call to `convert(Union{Int64, String}, globalVariable)` can be inserted here… Or can it?

Oh, yes. It inserts a convert. But since it can’t know which instance of `convert` to call, it will do runtime dispatch based on the current value of the global `globalVariable`. So it can’t inline, it can’t eliminate the convert, it has to find out which one to call at run time.

When there are relatively few possible types (four or less, I think), runtime dispatch is fairly fast, so in this case there might be some help in declaring a type for `y`.

The typical performance trick if such instability can’t be removed, is to use a function barrier:

```julia
y = globalVariable
g(y)
...
g(y::Integer) = ... whatever ...
g(y::String) = ... whatever ...

```

Inside the new function `g`, there is no instability. So it will run fast.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 29, 2024, 1:41pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/11 "2024-10-29T13:41:49Z")

</div>

Ok seems like the compiler behavior here is to change

```julia
y = glob

```

to

```julia
y = convert(Union{Int64, String}, glob)

```

Which it complains it cannot do because, naturally, there is no such function defined.

```julia
julia> y = glob
ERROR: MethodError: Cannot `convert` an object of type
  Vector{Int64} to an object of type
  Union{Int64, String}
The function `convert` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  convert(::Type{T}, ::T) where T
   @ Base Base.jl:126

```

Given what was posted previously this is nothing new, really.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 29, 2024, 1:43pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/12 "2024-10-29T13:43:29Z")

</div>

> [@sgaure](#):
>
> But since it can’t know which instance of `convert` to call, it will do runtime dispatch based on the current value of the global `globalVariable`. So it can’t inline, it can’t eliminate the convert, it has to find out which one to call at run time.

This is the key point, I think. Thanks. This is going to take me down another wormhole figuring out how Julia does runtime aka dynamic dispatch. I’m sure there are documentation pages about this so I will go and try and look for them.

Thanks for all the responses.

---

<div class="post-metadata">

**Author:** ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)\
**Post date:** [October 29, 2024, 2:05pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/13 "2024-10-29T14:05:58Z")

</div>

> [@world-peace](#):
>
> This is going to take me down another wormhole figuring out how Julia does runtime aka dynamic dispatch. I’m sure there are documentation pages about this so I will go and try and look for them.

This is perhaps a place to start: [https://fzn.fr/projects/lambdajulia/paper.pdf](https://fzn.fr/projects/lambdajulia/paper.pdf)

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 29, 2024, 3:48pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/14 "2024-10-29T15:48:28Z")

</div>

Thank you for the link. I did a bit of searching earlier and didn’t find much in the way of results.

---

<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 29, 2024, 8:47pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/15 "2024-10-29T20:47:52Z")

</div>

> [@sgaure](#):
>
> This is perhaps a place to start:

Not sure if I would recommend that to a beginner. Probably better to start with the docs and playing in the REPL.

Also, FTR, the paper is a bit outdated if I remember correctly. Although it’s certainly a nice read, and it gives links to relevant Github issues.

---

<div class="post-metadata">

**Author:** ![world-peace](https://avatars.discourse-cdn.com/v4/letter/w/9f8e36/32.png) [@world-peace](https://discourse.julialang.org/u/world-peace)\
**Post date:** [October 30, 2024, 10:12am UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/16 "2024-10-30T10:12:50Z")

</div>

> [@nsajko](#):
>
> Not sure if I would recommend that to a beginner.

I know some type theory - I just don’t know how Julia implements it.

---

<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 30, 2024, 11:52am UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/17 "2024-10-30T11:52:45Z")

</div>

Some pointers to relevant documentation:

- In the manual:
  - [Types](https://docs.julialang.org/en/v1.12-dev/manual/types/)
  - [Methods](https://docs.julialang.org/en/v1.12-dev/manual/methods/)

- In the base docs:
  - The [`<:`](https://docs.julialang.org/en/v1.12-dev/base/base/#Core.:%3C:) doc string. It’s much expanded in v1.12.

- In the developer docs:
  - [More about types](https://docs.julialang.org/en/v1.12-dev/devdocs/types/#More-about-types)
    - NB: I feel that the start of the article, which draws the “types as sets of values” analogy is somewhat misleading. While this is a useful analogy, it’s not perfectly accurate for Julia’s type system: there exist types which are not equal but have the same sets of values. For example, on versions of Julia prior to v1.12, this doesn’t hold: `Tuple <: Union{Tuple{}, Tuple{Any,Vararg}}`. The fact that this is fixed on nightly Julia is nice, and also shows that the subtyping isn’t fixed in stone.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [October 30, 2024, 1:59pm UTC](https://discourse.julialang.org/t/the-runtime-type-and-the-variable-type/121868/18 "2024-10-30T13:59:14Z")

</div>

You might also find this old StackOverflow answer of mine helpful at a high level. It’s also old, but nothing fundamental has changed to my knowledge.

> <https://stackoverflow.com/questions/32144187/how-does-julia-implement-multimethods/32148113#32148113>
