Egy régi cikket olvasgatva eszembe jutott egy gondolatom, amit már meg akartam írni egy ideje, de sose jutottam hozzá. Az ősi programozómondás szerint a programozó erénye a lustaság. (Ha az olvasó nem érti, hogy miért, akkor nyilván nem programozó, és nem biztos, hogy a cikk további részében örömét leli.) De nekem sokszor úgy tűnik, hogy ezt az erényt nem hasznosítjuk eléggé, vagy nem szolgáljuk ki eléggé, vagy tudomisén mit.
Itt vannak például a különböző nyelvek. Gyakorta megesik, hogy ráakad az ember egy klassz algoritmusra valahol már lekódolva, föl is használná, de – másik nyelven van. A programozó ilyenkor mit tehet, lefordítja. Csak hát ez ellentmond az ősi alapelvnek, hiszen a fordításnál elkövethetünk olyan hibákat, amiket a copy-paste technikával biztosan nem.
De voltaképpen mi a különbség a programnyelvek között? Ha lecsupaszítjuk a dolgot, akkor annyi, hogy minden nyelvet és nyelvjárást egy-egy szoftver valósít meg, és mindegyiknek megvannak a saját szintaktikai és szemantikai szabályai. Egyik sem tűnik olyasminek, ami visszavonhatatlanul megakadályozza a nyelvek egyesítését. Ha egy nyelv, mondjuk a PHP 6 értelmezésére már megírtak egy programot (a PHP programot, ami letölthető a PHP.netről), akkor ugyanígy meg lehet írni még egy programot. És ha egy nyelv, mondjuk a Spectrum BASIC szintaxisa és szemantikája különbözik a PHP-étől, akkor lehet írni olyan programot, ami összehozza a kettőt.
Ez nyilvánvaló. Tessék egy forrásszöveg példa gyanánt.
10 PRINT "Hello, world!" #include <iostream> int main() { std::cout << "Hello, world!n"; } : HELLO ( -- ) ." Hello, world!" CR ; HELLO print [Hello, world!] program hello; begin writeln('Hello, world!'); end. echo "Hello, world!";
A programozó olvasó ránézésre fel fogja ismerni, hogy a forrásszöveg valójában hat forrásszöveg, éspedig ugyanazt a Hello, world! programot másoltam ide öt nyelven. Sőt azt is ránézésre fel fogja ismerni, hogy a nyelvek sorban: sorszámozott BASIC, C++, Forth, Logo, Pascal és PHP. A programozó olvasó olyan forrásszöveget is kitűnően meg fog érteni, aminek nyelvét nem vagy hibásan azonosítja, például ezt:
function main() { message("Hello, world!") }
Az olvasó tudja ebből, hogy Baan Tools nyelven van, 3GL formátumban? Én nem tudnám, mégis minden betűjét hibátlanul megértem. (A példák természetesen a Wikibooks listájából valók.)
Én még azt se gondolom, hogy a gépet meg kellene tanítani felismerni a programnyelvet, ámbár ha ezt tennénk, az se lenne csoda. A számítástechnika történetének egyik folyamata arról szól, hogy a gépeket megtanítjuk olyan dolgokra, amiket mi mindig is tudtunk. Tudnak papírra írni, olvasni (OCR), sakkozni, zenélni – de volt idő, amikor ezeket még nem tudták. De programnyelvet felismerni nem feltétlenül kellene megtanítani őket.
Én a következőt képzeltem el. Lehetne írni egy olyan fejlesztőkörnyezetet, ami Minden Nyelven Tud. Hiszen a nyelvek végeredményben csak a szintaxisban és a mögötte levő szemantikában különböznek. (Ez így nem igaz, de momentán megteszi.) A mai programnyelvek már mind parsert használnak, egy külön programot, ami elolvassa a forráskódot és lefordítja egy köztes kódra, amit aztán a fordító vagy az értelmező feldolgoz. Akkor mi lenne, ha több parser lenne a fejlesztőkörnyezetben?
Egy olyan parsert képzeltem el, ami egy központi részből és sok-sok pluginból áll. Minden nyelvhez, nyelvjáráshoz egy plugin jár, és a központi rész választja ki, hogy mikor melyiket válassza. Például így:
#BASIC 10 PRINT "Hello, world!" #C #include <iostream> int main() { std::cout << "Hello, world!n"; } #FORTH : HELLO ( -- ) ." Hello, world!" CR ; HELLO #LOGO print [Hello, world!] #PASCAL program hello; begin writeln('Hello, world!'); end. #PHP echo "Hello, world!";
Például így. A parser központi része látja a nyelveket jelölő direktívákat és meghívogatja a pluginokat. Azok lefordítják a nyelvükön írt részeket, és egyetlen köztes kódot (Pascal-terminológiával P-kódot) kapunk, amit aztán egyetlen fordítónak vagy értelmezőnek lehet föltálalni.
Miért jó ez? Több okból. Ha találunk a neten egy alkalmas algoritmust, azt fordítgatás nélkül beilleszthetjük a programunkba. Ugyanazon a projekten úgy dolgozhat több programozó, hogy mindenki a neki legjobban megfelelő nyelven írhatja a neki jutó részeket. És a különböző nyelvek profitálhatnak egymás képességeiből.
Azt mondtam, hogy a nyelvek csak a szintaxisban és a szemantikában különböznek, és hozzátettem, hogy ez így nem igaz. Persze hogy nem igaz, hiszen a nyelvek mögött egy szoftver van, ami különféle rutinokat tartalmaz. Például a Logo minden interpretációja tartalmazza a teknőcgrafikát, amit a többi nyelvben úgy kell külön létrehozni, ha szükség van rá.
Ha több parserünk van, amik ugyanazt a pszeudokódot állítják elő, az csak úgy ér valamit, ha a fordítóban benne vannak a szükséges rutinok is. Vagyis ha tudunk Logót interpretálni, akkor a teknőcgrafikához szükséges rutinoknak is benne kell lenniük a fordítóban. De ha benne vannak a fordítóban, akkor a többi nyelvből is elérhetjük őket. Hogyan? Ki kell dolgozni rá a módszereket. Ilyesféléket:
#TRANSLATE FROM PHP forward(#VAR#); END FROM TO LOGO forward #VAR# END TO END TRANSLATE
Innentől PHP-ben a forward() függvény a Logo-beli forward utasítást fogja jelenteni.
Szerintem nyereség lenne egy ilyet összehozni.