external în Kotlin

external declară o funcție implementată în afara lui Kotlin: în cod nativ prin JNI pe JVM, sau în JavaScript pentru Kotlin/JS.

Sintaxă
external fun numeFunctie(param: Tip): Tip     // fără corp: implementarea este în cod nativ (JNI)

// Kotlin/JS: declarație pentru cod JavaScript existent
external fun alert(mesaj: String)

Ce face external

O funcție external nu are corp: îi spui compilatorului că implementarea există în altă parte. Pe JVM, external este echivalentul lui native din Java: funcția este scrisă în C sau C++, compilată într-o bibliotecă (.so, .dll, .dylib) și încărcată cu System.loadLibrary("nume"). Legătura se face prin JNI (Java Native Interface), după numele clasei și al funcției.

Dacă apelezi funcția fără să fi încărcat biblioteca, JVM aruncă UnsatisfiedLinkError. În Kotlin/JS, external declară funcții, clase și variabile care există deja în JavaScript (în browser sau într-un pachet npm), ca să le poți apela cu verificare de tipuri.

Pentru majoritatea programelor nu ai nevoie de external. Pe JVM se folosește pentru biblioteci native (criptografie, procesare video, drivere), iar în Kotlin/Native interoperabilitatea cu C se face prin cinterop, nu prin external.

Exemple

Exemplul 1: Funcție nativă fără bibliotecă încărcată

Declarația compilează, dar biblioteca nativă nu există, deci apelul aruncă UnsatisfiedLinkError, prins aici ca programul să explice ce s-a întâmplat.

external fun calculeazaHash(text: String): Long

fun main() {
    try {
        println(calculeazaHash("Ana"))
    } catch (e: UnsatisfiedLinkError) {
        println("Biblioteca nativă lipsește: ${e.message}")
    }
}

Rezultat

Biblioteca nativă lipsește: 'long MainKt.calculeazaHash(java.lang.String)'

Exemplul 2: Cu bibliotecă JNI (nu rulează aici)

Partea în C implementează funcția cu numele cerut de JNI (Java_ + clasă + funcție). Kotlin încarcă biblioteca o dată, la pornire, apoi apelează funcția ca pe oricare alta.

// hash.c, compilat în libhash.so:
// JNIEXPORT jlong JNICALL Java_MainKt_calculeazaHash(JNIEnv *env, jclass cls, jstring text) { ... }

external fun calculeazaHash(text: String): Long

fun main() {
    System.loadLibrary("hash")   // caută libhash.so în java.library.path
    println("Hash pentru Ana: ${calculeazaHash("Ana")}")
}

Rezultat (cu libhash.so compilată și java -Djava.library.path=.)

Hash pentru Ana: 2045623

Greșeli frecvente

  • Un corp pentru o funcție external: eroare external declaration cannot have a body.
  • Numele funcției C nu corespunde cu clasa generată de Kotlin: funcțiile din main.kt stau în clasa MainKt, deci numele JNI este Java_MainKt_...; altfel apare UnsatisfiedLinkError chiar dacă biblioteca e încărcată.
  • Uitarea lui System.loadLibrary înainte de primul apel.

Comenzi înrudite

  • expect și actual: expect declară în codul comun ceva ce fiecare platformă (JVM, Android, iOS, JS) implementează separat cu actual.
  • annotation class și ținte de adnotare: annotation class declară o adnotare (@Nume) care adaugă informații la cod; @field:, @get:, @file: aleg exact unde se pune.
  • kotlinc: Compilatorul Kotlin din linia de comandă: transformă fișierele .kt într-un program care rulează pe JVM.
  • fun: fun declară o funcție: un bloc de cod cu nume, care primește parametri și poate returna un rezultat.