Gli FFI sono basati su C. Assomigliano a C. E quindi, le interfacce basate su FFI sono limitate a C.
Userò Lua come esempio, poiché è quello che mi è più familiare.
Se stavi usando l'API Lua C, potresti esporre un sistema a Lua che guarda e si comporta come se Lua si aspettasse di farlo. Potrebbe esporre oggetti che il codice Lua potrebbe memorizzare e chiamare come le altre cose di Lua: variable_name.member_func(...)
e così via. Potresti persino implementare l'overloading delle funzioni.
Questo non è possibile direttamente tramite FFI. Oh certo, l'FFI di LuaJIT ti consente di applicare i metatables ai tipi. Ma ciò accade dopo la parte FFI quando si caricano le strutture dati. Richiede lavoro manuale nello script. Considerando che farlo in C API richiede zero lavori di script; per te è stata creata un'API corretta.
Ed è importante esaminare quale sarebbe una "API appropriata". Come la maggior parte dei linguaggi di scripting, Lua consente molte cose che C non fa. Con l'API Lua C, puoi esporre a funzioni Lua C che:
- Prendi numeri arbitrari di parametri.
- Restituisce numeri arbitrari di valori.
- Gestisci direttamente i valori dei parametri Lua (dati utente, tabelle, funzioni, ecc.)
- Fornisci errori tramite il meccanismo di errore Lua standard.
- Restituisci i dati compatibili con l'istruzione generica
for
di Lua.
Le interfacce create da FFI non possono fare nulla direttamente. Di nuovo, puoi sempre scrivere wrapper e così via per loro, ma poi stai scrivendo un wrapper.
E proprio per interesse aggiunto, LuaJIT rompe le convenzioni di Lua sull'indicizzazione degli array. Nella normale Lua, gli array sono sempre basati su 1. Ma con l'FFI di LuaJIT, gli array che vengono allocati sono a base zero come C. Qualunque cosa si possa desiderare di dire su quale convenzione sia meglio, avere entrambe le convenzioni contemporaneamente è molto peggio di entrambe.
Gli FFI hanno una tendenza verso quel tipo di interfaccia. Poiché sono distorti verso C, a volte entrano in conflitto con le convenzioni del linguaggio di scripting.
Poi c'è il problema della sicurezza. Con una FFI, in particolare una come LuaJIT, stai praticamente permettendo che il codice C sia scritto in Lua. Quindi, invece di isolare gli elementi non sicuri del tuo programma in alcune librerie C, stai permettendo agli aspetti non sicuri di C di infiltrarsi nell'ambiente di scripting. E invece di ottenere errori Lua che possono essere gestiti e recuperati, di solito si verificano arresti anomali.
Ciò renderà molto più difficile il debug poiché la maggior parte degli ambienti di scripting non ha i debugger validi come quelli C / C ++.
A seconda delle esigenze, questi problemi di sicurezza potrebbero essere completamente inaccettabili. Non vorrei che la gente potesse mandare in crash il processore di script Lua di Wikipedia sul server, solo perché qualcuno ha casualmente fatto un brutto cast di FFI in uno script Lua.
Alla fine della giornata, FFI è la soluzione migliore per l'interfaccia con sistemi a cui non è mai stato previsto l'accesso dalla lingua host. In quanto tale, un'interfaccia oddball è meglio di nessuna interfaccia. Puoi isolare le stranezze per renderlo più simile alla lingua host.
Ma se stai scrivendo un sistema che stai progettando esponendo a un linguaggio di scripting, darai ai programmatori di script un'esperienza di programmazione molto più ragionevole. Ciò non significa che non puoi utilizzare FFI per rendere alcune cose più veloci (array di grandi dimensioni, ecc.). Ma se puoi evitarlo, non dovresti semplicemente lanciare un'interfaccia DLL raw a qualcuno se puoi aiutarlo.