liveBook · Manning

Type-safe API

As explained in Kotlin in Action, 2E

A type-safe API is an interface whose operations prevent invalid type combinations through compile-time type checking.

A type-safe API hides unavoidable unchecked logic behind a controlled interface, so callers cannot combine a type with the wrong validator or operation. section 11.3.6

Typed validator registry

A private map stores validators for different classes, while generic registerValidator and get functions connect each KClass<T> to FieldValidator<T>. The implementation contains one unchecked cast; callers receive the correct validator, and an incorrect call such as Validators[String::class].validate(42) fails at compile time. section 11.3.6

The pattern separates safe usage from unsafe storage:

  • A heterogeneous map uses KClass<*> and FieldValidator<*> because the stored generic arguments are unknown. section 11.3.6
  • Direct retrieval prevents input because FieldValidator<*> cannot safely accept a value of an unknown type. section 11.3.6
  • Encapsulation localizes the unchecked cast and prevents callers from corrupting the collection. section 11.3.6
Listing 11.21 Encapsulating access to the validator collection
object Validators {
    private val validators =                                           #1
            mutableMapOf<KClass<*>, FieldValidator<*>>()
 
    fun <T: Any> registerValidator(
            kClass: KClass<T>, fieldValidator: FieldValidator<T>) {
        validators[kClass] = fieldValidator                            #2
    }
 
    @Suppress("UNCHECKED_CAST")                                        #3
    operator fun <T: Any> get(kClass: KClass<T>): FieldValidator<T> =
        validators[kClass] as? FieldValidator<T>
                ?: throw IllegalArgumentException(
                "No validator for ${kClass.simpleName}")
}
 
fun main() {
    Validators.registerValidator(String::class, DefaultStringValidator)
    Validators.registerValidator(Int::class, DefaultIntValidator)
 
    println(Validators[String::class].validate("Kotlin"))
    // true
    println(Validators[Int::class].validate(42))
    // true
}

Inspect the complete Kotlin registry implementation, including registration, lookup, encapsulation, and the localized unchecked cast. section 11.3.6

How Kotlin in Action, 2E covers it

How deep it goes
Explains star projections, unsafe casts, failure cases, and generic encapsulation, stopping short of broader implementation alternatives.
Examples
Uses Kotlin validator interfaces, KClass-keyed maps, star-projected lists, compile-time errors, and a ClassCastException.
What you can do after
Apply generic encapsulation to expose containers that reject incorrect type combinations at compile time.
How it connects
Connects generics, variance, star projections, unchecked casts, encapsulation, and Java interoperability.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Kotlin in Action, 2E. The section links point to the parts of the book it draws on.