A fordító és az értelmező közötti különbség
On december 31, 2021 by adminA definícióik alapján a fordító és az értelmező közötti különbség elég egyértelműnek tűnik:
- Az értelmező olyan program, amely közvetlenül végrehajtja a programozási nyelven írt utasításokat
- A fordító olyan program, amely átalakítja a forráskódot egy alacsony(er)-szintű nyelven
Ha azonban mélyebbre ásunk, némi elmosódást találunk a kettő között.
Tény, hogy egy értelmező lefordíthatja a forrásnyelvet egy köztes formába, hogy felgyorsítsa a végrehajtást. Általában ez történik egy olyan nyelvnél, ami virtuális gépre támaszkodik. Ez természetesen néhány kérdéshez vezet:
Minden nyelv, amely virtuális gépet használ, értelmezett?
Valójában mindegyik fordított?
Mondhatjuk, hogy mindkettő: egy nyelvet először lefordítanak egy köztes formára/nyelvre, majd ezt a köztes dolgot futáskor értelmezik. Ami egy másik kérdéshez is vezet, a fordítót és az értelmezőt nem egy programnak kell elképzelni, hanem inkább egy programcsoportnak, rendszernek. Amit te, mint felhasználó, fordítónak gondolsz, az valójában több programot is tartalmazhat. Például tartalmazhat egy linkelőt is: egy olyan programot, amely különböző objektumfájlokat egyesít egy fájlban, hogy az könnyebben használható legyen. Valami hasonlót mondhatnánk az interpreterről is.
Meg tudsz nekem mindent mondani a fordítókról & az értelmezőkről?
Miből áll össze tehát egy fordító vagy egy interpreter? Az ilyen kérdésekre pontos és technikai választ az akadémián lehetne keresni. Vagy a StackOverflow-n találhatsz vitákat ezekről a kérdésekről.
Az, ami igazán számít nekünk, fejlesztőknek, vagy akár nekünk, egy nyelv alkotóinak, hogy mi a különbség a velük való munka során. Mindkettőnek vannak előnyei és hátrányai, sőt, néhány nyelvnek lehet értelmezője és fordítója is, vagy akár több is. Ezt fogjuk látni.
A lényeg továbbra is áll: az értelmező most hajtja végre a kódot, a fordító pedig előkészíti a forráskódot egy későbbi végrehajtásra. Minden gyakorlati különbség ezekből az eltérő célkitűzésekből ered.
Hogyan terjeszthetünk egy programot
A gyakorlati szempontból az egyik fontos különbség az, hogy a fordító önálló programot generál, míg az értelmezett programnak mindig szüksége van az értelmezőre a futtatáshoz.
Amikor már van egy lefordított program, akkor futtathatjuk anélkül, hogy bármi mást telepítenünk kellene. Ez leegyszerűsíti a terjesztést. Másrészt a futtatható egy adott platformon működik: különböző operációs rendszereknek és különböző processzoroknak különböző lefordított változatokra van szükségük. Például egy lefordított C++ program működhet egy x86-os processzorral rendelkező számítógépen, de egy ARM-chippel rendelkező számítógépen nem. Vagy működhet egy Linux rendszeren, de egy Windows rendszeren nem.
Ha egy programot tolmácsolunk, akkor ugyanazt a példányt különböző platformokon lévő felhasználóknak is terjeszthetjük. Nekik azonban olyan értelmezőre lesz szükségük, amely az adott platformon fut. Terjesztheted az eredeti forráskódot vagy egy köztes formát. Az értelmezőt intuitív módon így tekinthetjük: olyan, mint a eval
függvény a JavaScriptben. Mindenhol működik, ahol a JavaScript működik, de a futtatásához szükség van az adott platformhoz tartozó JavaScript-értelmezőre.
Platformok közötti támogatás
Ez egy technikai különbség, amely fontos valós következményekkel jár: egy értelmezett programozási nyelvvel könnyebb platformok közötti programokat készíteni.
Ez azért van, mert a legtöbbször csak az értelmező platformjára készítünk programot. Maga az értelmező lesz az, amelyik lefordítja azt a valódi platformnak (pl. Windows/Linux és x86/ARM) megfelelő formára. Természetesen az egyes platformok között még mindig vannak különbségek, amelyekkel tisztában kell lennie. Egy gyakori példa erre a könyvtárelválasztó karakter.
A program lefordításakor ehelyett magadnak kell gondoskodnod az egyes platformok közötti apró különbségekről. Ez részben azért történik, mert a lefordított nyelvek általában alacsony(abb) szintű nyelvek, mint például a C++, így alacsonyabb hozzáférést biztosítanak a rendszerhez, és így nagyobb felelősséget. A másik ok azonban az, hogy az összes könyvtárnak, amit használsz, magának is támogatnia kell a különböző platformokat. Tehát, ha nem támogatják a Windowst, akkor nem tudod támogatni a Windowst.
A sebességnek több arca van
A sebesség esetében ismét egyfajta paradoxonnal állunk szemben: egy fordító egyszerre gyorsabb és lassabb, mint egy értelmező. Sokan tudják, hogy egy lefordított program sokkal gyorsabb, mint egy értelmezett, de ez nem a teljes kép. Egy lefordított program gyorsabban fut, mint egy értelmezett program, de egy program lefordítása és futtatása több időt vesz igénybe, mint egy program egyszerű értelmezése.
A fordító valóban gyorsabb programokat készít. Ez alapvetően azért történik, mert minden utasítást csak egyszer kell elemeznie, míg az értelmezőnek minden egyes alkalommal elemeznie kell. Továbbá a fordító képes optimalizálni az általa előállított futtatható kódot. Ez egyrészt azért van, mert pontosan tudja, hogy hol fog futni, másrészt a kód optimalizálása időt vesz igénybe. Időt, ami túl lassúvá tenné az értelmezést.
Futási sebesség kontra fejlesztési sebesség
Azt gondolhatnánk, hogy ez apróság: ha lefordítunk egy programot, az gyorsabban fut, a fordítási idő nem számít. Ez általában a régi iskola véleménye. És kétségtelen, hogy a kapott program többször fut le, mint ahányszor lefordították. Tehát kit érdekel, ha a fejlesztés több időt vesz igénybe? Nos, az biztos, hogy a fejlesztéshez egy “hozza a fájdalmat” hozzáállás kell, ami némileg csodálatra méltó. De mi van akkor, ha a futási időnyereség nem releváns, míg a fejlesztői termelékenység csökkenése jelentős?
Egy dolog, ha operációs rendszert készítesz, és egy másik, ha szelfi alkalmazást készítesz. Még az is lehet, hogy a felhasználóidnak jobban tetszik a futási idő sebességében nem is észrevehető veszteség, cserébe a funkciók gyorsabb eléréséért. Nincs mindenre egyformán érvényes válasz: bizonyos kontextusokban a termelékenység többet számít, mint a sebesség, másokban pedig éppen fordítva.
A hibakeresés rejtelmei
Van egy másik sajátos szempont, ami végül is bizonytalanabb, mint amit az ember szempontnak tart: a hibakeresés. Papíron a hibakeresés könnyebb egy interpreter használata közben, mint egy fordító használata közben. Ez több okból is igaz:
- Az interpreterrel a futtatható állománynak egy változata van; nincs szükség egy hibakereső verzióra a fejlesztéshez és egy kiadásra a végfelhasználónak
- az interpreter használatával kevesebb a platformspecifikus hiba
- mert az interpreter menet közben átalakítja a kódot, a forráskódból származó információ továbbra is rendelkezésre áll
- mivel az értelmező egyszerre egy utasítást hajt végre, könnyebb megtalálni a hibát
A fejlesztőeszközök által okozott különbség
Míg mindez a gyakorlatban igaz, ez talán kevésbé lényeges, mint amilyennek tűnik. Valójában, ha végiggondolod a tapasztalataidat, valószínűleg úgy találod, hogy a JavaScript hibakeresése nehezebb, mint a C++ hibakeresése. Miért van ez így? Részben maguknak a nyelveknek a felépítése. A JavaScript dinamikus tipizálást használ, míg a C++ statikus tipizálást. Ez utóbbi megkönnyíti a hibák korai észlelését. De végső soron a fejlesztőeszközökön múlik a dolog. A C++-t kézzel fordítani nehéz, ezért a legtöbb ember IDE-t használ a fejlesztéshez. Ezzel szemben a JavaScriptben való fejlesztéshez könnyen használhatunk szövegszerkesztőt és parancssori eszközöket.
Ez gyakorlatilag azt jelenti, hogy ha C++-ban fejlesztünk, akkor a C++-ban is tudunk hibakeresést végezni. Ehelyett fejleszthet JavaScriptszel anélkül, hogy tudná, hogyan kell JavaScriptben megfelelő hibakeresést végezni.
Ezzel együtt, ha ugyanabba a kontextusba helyezzük őket, mindkettőt egy-egy nagyszerű IDE-vel és támogató eszközökkel, a helyzet visszaáll a normális kerékvágásba. Valóban sok értelmezett környezetet használnak azok, akik meg akarnak tanulni egy új nyelvet használni. Könnyebb tesztelni, és megtalálni, mi a jó és mi a rossz, ha megnézzük, mi történik soronként és valós időben.
Összefoglaló
Láttuk a fő különbségeket, amelyek egy fordító és egy értelmező között számítanak. Ennél is fontosabb, hogy láttuk, hogy a különböző filozófiák következményei fontosabbak, mint a technikaiak. Röviden, vannak olyan kultúrák, amelyek bizonyos technikai döntésekkel járnak, amelyek végül önmagukban is fontosak. Ha sebességet és könnyű fejlesztést akarsz, akkor az összes technológiát a sebesség érdekében fogod kiválasztani, nem csak egyet. És a felhasználóid követni fogják a példádat.
Ez egy döntő fontosságú szempont, amit át kell gondolnod, különösen, ha saját programozási nyelvet akarsz létrehozni. Rasmus Lerdorf a PHP-t úgy alkotta meg, hogy könnyen használható legyen. És valóban hihetetlenül könnyen használható volt az alternatívákhoz képest, legalábbis a megalkotása idején. De inkább könyvtárként indult, mint nyelvként. És bár sokat fejlődött, még mindig szenved a kezdetektől. Még mindig lehet jó PHP kódot készíteni, de a szokásosnál kevesebb felhasználója teszi ezt. Mert ha csak arra van szükséged, hogy valami működjön, biztonság, karbantartás, stb. minden más később jön.
Ha tudni akarod, hogyan tudsz gyakorlatilag interpreter vagy fordítóprogramot készíteni a nyelvedhez, akkor érdemes megnézned a programozási nyelv készítéséhez szükséges forrásokat. Ha ezt is meg akarod tanulni, és mindazt, amire szükséged van a saját nyelved létrehozásához, akkor csak válassz egy nagyszerű, gyerekek és felnőttek által egyaránt kedvelt könyvet arról, hogyan lehet pragmatikus, könnyű nyelveket létrehozni.
5 dolog, amit jól kell tenned, ha nyelvet építesz
E-mailben megkapod az ellenőrző listát, és további tippeket kapsz a nyelvek építéséhez
Vélemény, hozzászólás?