<p>Most if not all OO languages have some way to determine whether an object belongs to a given class at runtime. In some languages -- both interpreted (like JS) and compiled (like Objective-C) -- classes are objects that exist at runtime, and an object can just be asked for its class (<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor" rel="noreferrer"><code>constructor</code></a> and <a href="https://developer.apple.com/documentation/objectivec/nsobject/1571950-class?language=objc" rel="noreferrer"><code>class</code></a> respectively).</p>
<p>However, I'm curious what other strategies exist. For example, I don't believe C++ has class objects, so how does <code>dynamic_cast</code> work?</p>

<implementation><object-oriented><rtti>
How can runtime type checks be implemented?
CC BY-SA 4.0
2023-05-22T22:19:01.123Z
[Here](https://www.youtube.com/watch?v=QzJL-8WbpuU) is a good talk from Cppcon about `dynamic_cast` implementation.
chrysante
<h1>Fat Pointers</h1>
<p>A &quot;fat pointer&quot; is a pointer that stores additional data besides an address. For the purposes of dynamic dispatch and type checking, this data can be a pointer to a vtable which stores type information such as associated functions and a type ID. This approach is taken by Go and Rust, among others.</p>
<p>An example adapted from Rust's documentation:</p>
<pre class="lang-rs prettyprint-override"><code>use std::any::Any;
use std::mem::size_of;

pub fn print_if_string(s: &amp;dyn Any) {
    // `&amp;dyn Any` is a fat pointer, the size of two 'regular' pointers
    assert!(size_of::&lt;&amp;dyn Any&gt;() == 2 * size_of::&lt;&amp;String&gt;());

    println!(&quot;Object has type id `{:?}`&quot;, s.type_id());
    
    if let Some(string) = s.downcast_ref::&lt;String&gt;() {
        println!(&quot;It's a string({}): '{}'&quot;, string.len(), string);
    } else {
        println!(&quot;Not a string...&quot;);
    }
}
</code></pre>

CC BY-SA 4.0
2023-05-23T16:16:28.303Z
2023-05-23T16:16:28.303Z
Olive
CC BY-SA 4.0
2023-05-23T16:27:37.010Z
What is the type ID in Rust? In Swift, as in ObjC, it’s a pointer to a type object.
Bbrk24
CC BY-SA 4.0
2023-05-23T16:36:06.870Z
As an implementation detail, Rust's `TypeId` is currently a 64-bit integer which the compiler guarantees is unique for every type.
Olive
<p>In contrast to have some marker at a pointer/reference to the object (this might rely on the assumption that the language is garbage collected, that it has a global, be it internal only or externally exposable, list of all its objects), I remember that C++ <code>dynamic_cast</code> does not work if the RTTI (run-time type information) feature is disabled. This is because <code>dynamic_cast</code> couldn't perform a class inheritance chain lookup for an address to an object to determine whether a cast is legal or not, if RTTI doesn't store and internally provide such information.</p>
<p>A simple (naive?) approach could be to just spend a little bit of extra memory for each object in memory, by adding a class/type ID to it (that's probably why RTTI can be disabled for C++, to save the memory if the expense is not wanted/needed). Then, there could be an internal table/graph which gathers/loads/learns the inheritance chain (bake it into the program at compile time, if there's no strategy to do it dynamically during runtime?) between these classes represented by such internal ID. For a given object, it's class ID could be looked up in the class inheritance table/graph, which then allows to navigate the inheritance chain up and down, for type-checks, dispatch and what not.</p>
<p>Given OOP doing its object representation/handling is mostly just a number of such fields (organizing stuff in memory) anyway and mechanisms which act on these.</p>

CC BY-SA 4.0
2024-06-14T23:58:32.563Z
2024-06-14T23:58:32.563Z
skreutzer
CC BY-SA 4.0
2024-06-17T12:42:24.053Z
You are correct that dynamic_cast does not work in the absence of RTTI, but incorrect as to why. Please avoid speculation in answers.
Matthieu M.
# How can runtime type checks be implemented?
Posted by: username_0 on 2023-05-22
Most if not all OO languages have some way to determine whether an object belongs to a given class at runtime. In some languages -- both interpreted (like JS) and compiled (like Objective-C) -- classes are objects that exist at runtime, and an object can just be asked for its class ([`constructor`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/constructor) and [`class`](https://developer.apple.com/documentation/objectivec/nsobject/1571950-class?language=objc) respectively).

However, I'm curious what other strategies exist. For example, I don't believe C++ has class objects, so how does `dynamic_cast` work?
**Tags:** implementation object-oriented rtti
> **Comments:**
> **username_1**: [Here](https://www.youtube.com/watch?v=QzJL-8WbpuU) is a good talk from Cppcon about `dynamic_cast` implementation.  
---
## 2 answers
### Answer by username_2 on 2023-05-23. Score: 5
Fat Pointers
A "fat pointer" is a pointer that stores additional data besides an address. For the purposes of dynamic dispatch and type checking, this data can be a pointer to a vtable which stores type information such as associated functions and a type ID. This approach is taken by Go and Rust, among others.
An example adapted from Rust's documentation:
use std::any::Any;
use std::mem::size_of;

pub fn print_if_string(s: &dyn Any) {
    // `&dyn Any` is a fat pointer, the size of two 'regular' pointers
    assert!(size_of::<&dyn Any>() == 2 * size_of::<&String>());

    println!("Object has type id `{:?}`", s.type_id());
    
    if let Some(string) = s.downcast_ref::() {
        println!("It's a string({}): '{}'", string.len(), string);
    } else {
        println!("Not a string...");
    }
}
> **Comments:**
> **username_0** (2023-05-23): What is the type ID in Rust? In Swift, as in ObjC, it’s a pointer to a type object.  
> **username_2** (2023-05-23): As an implementation detail, Rust's `TypeId` is currently a 64-bit integer which the compiler guarantees is unique for every type.  
---
### Answer by username_3 on 2024-06-14. Score: -1
In contrast to have some marker at a pointer/reference to the object (this might rely on the assumption that the language is garbage collected, that it has a global, be it internal only or externally exposable, list of all its objects), I remember that C++ `dynamic_cast` does not work if the RTTI (run-time type information) feature is disabled. This is because `dynamic_cast` couldn't perform a class inheritance chain lookup for an address to an object to determine whether a cast is legal or not, if RTTI doesn't store and internally provide such information.

A simple (naive?) approach could be to just spend a little bit of extra memory for each object in memory, by adding a class/type ID to it (that's probably why RTTI can be disabled for C++, to save the memory if the expense is not wanted/needed). Then, there could be an internal table/graph which gathers/loads/learns the inheritance chain (bake it into the program at compile time, if there's no strategy to do it dynamically during runtime?) between these classes represented by such internal ID. For a given object, it's class ID could be looked up in the class inheritance table/graph, which then allows to navigate the inheritance chain up and down, for type-checks, dispatch and what not.

Given OOP doing its object representation/handling is mostly just a number of such fields (organizing stuff in memory) anyway and mechanisms which act on these.
> **Comments:**
> **username_4** (2024-06-17): You are correct that dynamic_cast does not work in the absence of RTTI, but incorrect as to why. Please avoid speculation in answers.  
---
