The public initMemoryView functions in multik-core/src/commonMain/kotlin/org/jetbrains/kotlinx/multik/ndarray/data/MemoryView.kt rely on unchecked casts across every DataType branch:
// MemoryView.kt:1058
@Suppress("UNCHECKED_CAST")
public fun <T> initMemoryView(size: Int, dataType: DataType, init: (Int) -> T): MemoryView<T> {
val t = when (dataType) {
DataType.ByteDataType -> MemoryViewByteArray(ByteArray(size, init as (Int) -> Byte))
// ... 7 more branches, each with an unchecked cast
}
return t as MemoryView<T>
}
The same pattern appears in the zero-init overload (MemoryView.kt:1035). The relationship between T and dataType is an unchecked invariant — passing mismatched arguments produces a ClassCastException on the first element access.
This is part of a broader pattern (see also #251 for NDArray.asType). In Kotlin stdlib, such casts are hidden behind @PublishedApi internal with documented invariants; here they sit on the public API surface.
Proposal
- Move the unchecked-cast implementation behind
@PublishedApi internal and expose a safe reified overload that derives dataType from T.
- Or: document the
T/dataType invariant explicitly and add a debug-time check.
- Audit other public functions for the same pattern.
The public
initMemoryViewfunctions inmultik-core/src/commonMain/kotlin/org/jetbrains/kotlinx/multik/ndarray/data/MemoryView.ktrely on unchecked casts across everyDataTypebranch:The same pattern appears in the zero-init overload (
MemoryView.kt:1035). The relationship betweenTanddataTypeis an unchecked invariant — passing mismatched arguments produces aClassCastExceptionon the first element access.This is part of a broader pattern (see also #251 for
NDArray.asType). In Kotlin stdlib, such casts are hidden behind@PublishedApi internalwith documented invariants; here they sit on the public API surface.Proposal
@PublishedApi internaland expose a safereifiedoverload that derivesdataTypefromT.T/dataTypeinvariant explicitly and add a debug-time check.