https://kotlinlang.org logo
#kotlin-native
Title
# kotlin-native
n

natario1

10/13/2023, 5:42 PM
What’s the point of
reinterpret<T>()
-ing a pointer, instead of simple (unchecked) casting? I thought the function performs checks based on the new
T
type, but looking at source code, it’s not even inline/reified. I don’t think the runtime receives the type information. So what kind of safety does
reinterpret()
provide? And related, is there any case were unchecked cast is legitimate? Maybe when size/align won’t change?
d

damian

10/13/2023, 7:03 PM
Seems that it calls
interpretCPointer
which is annotated with
TypedIntrinsic
, suggesting that it's implemented as a compiler intrinsic. I don't know the answer to your question though
e

ephemient

10/13/2023, 8:07 PM
reinterpret provides zero safety. the point is to bypass any other checks that e.g.
as
would normally provide
☝️ 3
n

natario1

10/14/2023, 9:22 AM
I feel more confused now 😄 so it’s about performance? I imagine that the unchecked cast from
CPointer<A>
to
CPointer<B>
would have almost zero cost, it’s even the same type. On the other hand the interpret call creates a new
CPointer
instance and has a
!!
.
j

Joakim Forslund

10/15/2023, 12:52 PM
.reinterpret() is just a forced typecast into the expected type, no safety. Nothing more
n

natario1

10/15/2023, 3:12 PM
I understand, thanks. It seems more expensive than
as
though, in which case, why is it not implemented as
as
under the hood?
e

ephemient

10/15/2023, 4:11 PM
I'm not sure why you think that
val y = x.reinterpret<T>()
doesn't return a new instance, it is like
val y = x
except that Kotlin now treats that part of memory as type
T
whether that is correct or not
n

natario1

10/15/2023, 5:20 PM
It’s what the source code suggests, see https://github.com/JetBrains/kotlin/blob/7a7d392b3470b38d42f80c896b7270678d0f95c3/[…]ative/Interop/Runtime/src/main/kotlin/kotlinx/cinterop/Types.kt .
interpretCPointer
takes
this.rawValue
(not
this
) and returns a CPointer. Of course there might be compiler/runtime magic under the hood
j

Joakim Forslund

10/15/2023, 5:31 PM
Its literally just a pointer of 8 bytes, in runtime it will map that to given type, there is no different penalty
n

natario1

10/15/2023, 5:54 PM
From the tests below, reinterpret is 6 times slower than casting on my machine. I’m not calling these a benchmark, I don’t have a lot of time to waste on this… but unless something new pops up in this thread, I think I’ll def spend some time removing reinterpret() from critical parts of my codebase.
Copy code
class PointerTests {
    @Test
    fun testInterpretPointer() {
        memScoped {
            var intPtr: CPointer<IntVar> = alloc<IntVar>().ptr
            var longPtr: CPointer<LongVar> = alloc<LongVar>().ptr
            measureTime {
                repeat(200000) {
                    longPtr = intPtr.reinterpret()
                    intPtr = longPtr.reinterpret()
                }
            }.also {
                println("testInterpretPointer: $it")
            }
        }
    }

    @Test
    fun testCastPointer() {
        memScoped {
            var intPtr: CPointer<IntVar> = alloc<IntVar>().ptr
            var longPtr: CPointer<LongVar> = alloc<LongVar>().ptr
            measureTime {
                repeat(200000) {
                    intPtr = longPtr as CPointer<IntVar>
                    longPtr = intPtr as CPointer<LongVar>
                }
            }.also {
                println("testCastPointer: $it")
            }
        }
    }
}
e

Edoardo Luppi

10/16/2023, 7:15 PM
So
reinterpret
is
unsafeCast
in K/JS?
If it is, sounds like a good ticket to align the two, makes it easier to switch platform
e

ephemient

10/16/2023, 7:17 PM
not quite, reinterpret only works between native pointer types
thank you color 1
e

Edoardo Luppi

10/16/2023, 7:18 PM
Oh then it's a bit different yeah,
unsafeCast
is an extension function on
Any
3 Views