Típusrendszer

A típusrendszer a programozási nyelvek  szabályainak halmaza, amelyek tulajdonságokat, úgynevezett típusokat rendelnek a programot alkotó különféle konstrukciókhoz  , például változókhoz , kifejezésekhez , függvényekhez vagy modulokhoz . A típusrendszer fő szerepe a programokban előforduló hibák számának csökkentése [1] azáltal, hogy interfészeket definiál a program különböző részei között, majd ellenőrzi ezen részek interakciójának konzisztenciáját. Ez az ellenőrzés történhet statikusan ( fordítási időben vagy dinamikusan ( futási időben ), vagy mindkettő kombinációjával.

Definíció

Pierce szerint a típusrendszer  egy eldönthető szintaktikai módszer bizonyos programviselkedések hiányának bizonyítására azáltal, hogy a konstrukciókat a számított értékek fajtája szerint osztályozza [2] .

Leírás

Egy egyszerű típusú rendszerre láthatunk példát a C nyelvben . A C program részei függvénydefiníciókként vannak megírva . A függvények hívják egymást. Egy függvény interfésze meghatározza a függvény nevét és a törzsébe továbbított értékek listáját. A hívó függvény felteszi a meghívni kívánt függvény nevét és azon változók nevét, amelyek az átadni kívánt értékeket tartalmazzák. A program végrehajtása során az értékek átmeneti tárolóba kerülnek, majd a végrehajtás átkerül a hívott függvény törzsébe. A hívott függvénykód eléri és használja az értékeket. Ha egy függvény törzsében az utasításokat azzal a feltételezéssel írjuk, hogy egy egész értéket kell átadni nekik feldolgozásra, de a hívó kód lebegőpontos számot adott át, akkor a meghívott függvény rossz eredményt fog kiértékelni. A C fordító ellenőrzi az egyes átadott változókhoz definiált típusokat a hívott függvény interfészén az egyes változókhoz definiált típusokhoz képest. Ha a típusok nem egyeznek, a fordító fordítási idejű hibát generál.

Technikailag a típusrendszer minden számított értékhez típust rendel , majd a számítások sorrendjének nyomon követésével megpróbálja ellenőrizni vagy bizonyítani, hogy nincsenek típusillesztési hibák . Az adott típusú rendszer meg tudja határozni, hogy mi okozza a hibát, de általában az a cél, hogy megakadályozzák, hogy a paramétereik bizonyos tulajdonságait feltételező műveletek olyan paramétereket kapjanak, amelyeknél ezeknek a műveleteknek nincs értelme – ezzel megelőzve a logikai hibákat . Ezenkívül megakadályozza a memóriacím-hibákat .

A típusrendszereket általában a programozási nyelvek részeként határozzák meg, és beépítik azok értelmezőibe és fordítóiba. A nyelv típusrendszere azonban bővíthető speciális eszközökkel , amelyek további ellenőrzéseket végeznek a nyelv eredeti gépelési szintaxisa alapján.

A fordító statikus értéktípust is használhat a tárolás optimalizálására, és az adott értékre vonatkozó műveletek algoritmikus megvalósításának kiválasztására. Például sok C-fordítóban egy típust float 32 bit képvisel az IEEE egypontos lebegőpontos műveletekre vonatkozó specifikációja szerint . Ennek alapján az ilyen típusú értékekhez (összeadás, szorzás és egyéb műveletek) egy speciális mikroprocesszor utasításkészlet kerül felhasználásra.

A típusokra vonatkozó korlátozások száma és számítási módja határozza meg a nyelv tipizálását. Ezen túlmenően a típuspolimorfizmus esetén a nyelv minden típushoz megadhatja a változó specifikus algoritmusok működését is. A típusrendszerek tanulmányozása a típusok elmélete , bár a gyakorlatban egy programozási nyelv adott típusrendszere a számítógép architektúrájának jellemzőire, a fordítóprogram megvalósítására és a nyelv általános képére épül.

Formai indoklás

A típusrendszerek formális igazolása a típuselmélet . A programozási nyelv tartalmaz egy típusrendszert a fordítási időben vagy futási időben történő típusellenőrzés végrehajtására , amely kifejezett típusdeklarációkat igényel, vagy önmagában következtet rájuk. Mark Manasse a következőképpen fogalmazta meg a  problémát [3] :

A típuselmélet által megoldott fő probléma a programok értelmességének biztosítása. A típuselmélettel kapcsolatos fő probléma az, hogy az értelmes programok esetleg nem úgy viselkednek, ahogyan azt szándékozták. Ennek a feszültségnek a következménye az erősebb típusú rendszerek keresése.

Eredeti szöveg  (angol)[ showelrejt] A típuselmélet alapvető problémája annak biztosítása, hogy a programoknak legyen jelentése. A típuselmélet alapja az, hogy az értelmes programoknak nem lehet problémás jelentéseket tulajdonítani. A gazdagabb típusú rendszerekre való törekvés ebből a feszültségből adódik. – Mark Massey [3]

A típus-hozzárendelési művelet, amelyet gépelésnek neveznek, jelentést ad bitkarakterláncoknak , például egy értéknek a számítógép memóriájában , vagy objektumoknak , például egy változónak . A számítógépnek nincs módja megkülönböztetni például a memóriában lévő címet egy kódutasítástól , vagy egy karaktert egy egész számtól vagy lebegőpontos számtól , mivel az ezeket a különböző jelentéseket képviselő bitsoroknak nincs olyan nyilvánvaló jellemzője, amely lehetővé tenné jelentésükkel kapcsolatos feltevések. A karakterláncokhoz típusbitek hozzárendelése biztosítja ezt az érthetőséget, így a programozható hardvert ebből a hardverből és szoftverből álló karakterrendszerré alakítja .

Típuskonzisztencia ellenőrzése

A típusellenőrzés és kényszerítés folyamata – típusellenőrzés vagy típusellenőrzés – elvégezhető akár fordítási időben statikus gépelés), akár futási időben (dinamikus gépelés). Köztes megoldások is lehetségesek (vö. szekvenciális gépelés ).

Ha a nyelvi specifikáció megköveteli a gépelési szabályok szigorú végrehajtását (vagyis bizonyos fokig csak azokat az automatikus típuskonverziókat engedje meg, amelyek nem veszítenek el információt), akkor egy ilyen nyelvet erősen beírtnak ; )  , egyébként gyengén beírtnak nevezzük . Ezek a kifejezések feltételesek, és nem használják formális indoklásban.

Statikus típusellenőrzés

Dinamikus típusellenőrzés és típusinformáció

Erős és laza gépelés

Típusbiztonság és memóriacímvédelem

Beírt és gépeletlen nyelvek

Egy nyelvet típusosnak nevezünk, ha az egyes műveletek specifikációi meghatározzák azokat az adattípusokat, amelyekre ez a művelet alkalmazható, ami azt jelenti, hogy más típusokra nem alkalmazható [4] . Például az " ez idézett szöveg " által képviselt adatok " " típusúak строка. A legtöbb programozási nyelvben nincs értelme egy szám karakterlánccal való elosztásának, és a legtöbb modern nyelv elutasítja az ilyen műveletet végrehajtó programot. Egyes nyelveken a program egy értelmetlen műveletet észlel a fordítás során ( statikus gépelés ), és a fordító elutasítja. Más esetekben a rendszer futás közben észleli ( dinamikus gépelés ), kivételt dobva ezzel .

A tipizált nyelvek speciális esetei az egytípusú nyelvek ( angol. egytípusú  nyelv ), vagyis az egytípusú nyelvek. Ezek általában szkript- vagy jelölőnyelvek , mint például a REXX és az SGML , amelyek egyetlen adattípusa a karakterlánc, amely karakteres és numerikus adatok megjelenítésére is szolgál.

A típusolatlan nyelvek, ellentétben a tipizált nyelvekkel, lehetővé teszik, hogy bármilyen műveletet végrehajtsunk bármilyen adaton, amelyet bennük tetszőleges hosszúságú bitláncok képviselnek [4] . A legtöbb assembly nyelv gépeletlen . Példák a magas szintű típus nélküli nyelvekre: BCPL , BLISS , Forth , Refal .

A gyakorlatban kevés nyelv tekinthető tipizáltnak a típuselmélet szempontjából (minden művelet engedélyezése vagy elutasítása), a legtöbb modern nyelv csak bizonyos fokú gépeltséget kínál [4] . Sok ipari nyelv lehetővé teszi a típusrendszer megkerülését vagy megszakítását, a típusbiztonságot a programvégrehajtás finomabb ellenőrzése érdekében ( gépelési szójáték ).

Típusok és polimorfizmus

A "polimorfizmus" kifejezés a kód azon képességére utal, hogy számos különböző típusú értéken futhat, vagy arra, hogy ugyanazon adatstruktúra különböző példányai különböző típusú elemeket tartalmazhatnak. Egyes típusrendszerek lehetővé teszik a polimorfizmust, hogy potenciálisan javítsa a kód újrafelhasználását : a polimorfizmussal rendelkező nyelvekben a programozóknak csak egyszer kell megvalósítaniuk az adatstruktúrákat, például egy listát vagy egy asszociatív tömböt , és nem kell egy implementációt kidolgozniuk minden egyes tervezett elemtípushoz. struktúrák tárolására. Emiatt egyes informatikusok néha „ általános programozásnak ” nevezik a polimorfizmus bizonyos formáinak használatát. A polimorfizmus indoklása a típuselmélet szempontjából gyakorlatilag megegyezik az absztrakció , a modularitás és esetenként az adataltípusosítással .

Kacsa gépelés

Speciális típusú rendszerek

Számos speciális típusú rendszert fejlesztettek ki bizonyos feltételek mellett bizonyos adatokkal való használatra, valamint programok statikus elemzésére . Ezek többnyire a formális típuselmélet gondolatain alapulnak, és csak kutatási rendszerek részeként használatosak.

Egzisztenciális típusok

Az egzisztenciális típusok, azaz az egzisztenciális kvantor (egzisztenciális kvantor) által meghatározott típusok egy típusszintű beágyazási mechanizmus : ez egy összetett típus, amely valamilyen típus megvalósítását rejti összetételében.

Az egzisztenciális típus fogalmát gyakran használják a rekordtípus fogalmával együtt a modulok és az absztrakt adattípusok ábrázolására , mivel céljuk elválasztani a megvalósítást az interfésztől. Például egy típus T = ∃X { a: X; f: (X → int); }leír egy modulinterfészt (azonos aláírású modulcsaládokat), amelynek van egy ilyen típusú adatértéke, Xés egy függvény, amely egy pontosan ugyanolyan típusú paramétert vesz fel, Xés egy egész számot ad vissza. A megvalósítás eltérő lehet:

Mindkét típus az általánosabb egzisztenciális típus altípusa, Tés konkrétan megvalósított típusoknak felel meg, így bármely érték, amely valamelyikhez tartozik, a típushoz is tartozik T. Ha t típus értéke T, akkor t.f(t.a)átmegy a típusellenőrzésen, függetlenül attól, hogy melyik absztrakt típushoz tartozik X. Ez rugalmasságot biztosít az adott megvalósításhoz megfelelő típusok kiválasztásában, mivel a külső felhasználók csak az interfész (egzisztenciális) típusának értékeihez férnek hozzá, és el vannak szigetelve ezektől a változatoktól.

Általában a típuskonzisztencia-ellenőrző nem tudja meghatározni, hogy egy adott modul melyik egzisztenciális típushoz tartozik. A fenti példában a intT { a: int; f: (int → int); }típusa is lehet ∃X { a: X; f: (int → int); }. A legegyszerűbb megoldás, ha minden modulhoz kifejezetten megadjuk a benne szereplő típust, például:

Bár az absztrakt adattípusokat és modulokat már régóta használják a programozási nyelvekben, az egzisztenciális típusok formális modellje csak 1988 -ban készült el [5] . Az elmélet egy másodrendű típusos lambda-számítás , amely hasonló az F rendszerhez , de az univerzális kvantifikáció helyett egzisztenciális kvantifikációt alkalmaz .

Az egzisztenciális típusok kifejezetten a Haskell nyelv kísérleti kiterjesztéseként érhetők el , ahol egy speciális szintaxis, amely lehetővé teszi egy típusváltozó használatát egy algebrai típusdefinícióban anélkül, hogy áthelyezné egy típuskonstruktor aláírásába , azaz nem növelné az aritását . 6] . A Java nyelv az helyettesítő karakteren keresztül az egzisztenciális típusok korlátozott formáját biztosítja . A klasszikus ML - stílusú let-polimorfizmust megvalósító nyelvekben az egzisztenciális típusok szimulálhatók úgynevezett " típusindexelt értékek " [7] segítségével .

Explicit és implicit típushozzárendelés

Sok statikus típusú rendszer, például a C és a Java, megköveteli a típusdeklarációt : a programozónak kifejezetten hozzá kell rendelnie egy adott típust minden változóhoz. Mások, mint például az ML - ben használt Hindley-Milner típusú rendszer és a Haskell , típuskövetkeztetést végeznek : a fordító a változók típusára következtet az alapján, hogy a programozó hogyan használja ezeket a változókat.

Például egy és az f(x,y)összeadást végrehajtó függvény esetében a fordító arra következtethet, hogy és számoknak kell lenniük – mivel az összeadási művelet csak számokhoz van definiálva. Ezért egy függvény meghívása valahol a programban a numerikustól eltérő paraméterekhez (például egy karakterlánchoz vagy egy listához) hibát jelez. xyxyf

A numerikus és karakterlánc-konstansok és kifejezések általában egy adott kontextusban fejeznek ki egy típust. Például egy kifejezés 3.14jelenthet valós számot , míg [1,2,3]lehet egész számok listája – általában egy tömb .

Általánosságban elmondható, hogy a típuskövetkeztetés akkor lehetséges, ha a típuselméletben alapvetően eldönthető . Sőt, még ha a következtetés eldönthetetlen is egy adott típusú elmélet esetében, gyakran sok valós program esetében lehetséges a következtetés. A Haskell típusú rendszer , amely a Hindley-Milner típusú rendszer egy változata, az Fω rendszer korlátozása az úgynevezett elsőrangú polimorf típusokra, amelyekre a következtetés eldönthető. Sok Haskell fordító tetszőleges rangú polimorfizmust ad kiterjesztésként, de ez eldönthetetlenné teszi a típuskövetkeztetést, ezért explicit típusdeklaráció szükséges. A típuskonzisztencia-ellenőrzés azonban továbbra is eldönthető, és az elsőrangú polimorfizmussal rendelkező programok esetében a típusok továbbra is származtathatók.

Egységes típusú rendszerek

Egyes nyelvek, mint például a C# , egységes típusrendszerrel rendelkeznek [8] . Ez azt jelenti, hogy a nyelv minden típusa, a primitívekig , egyetlen gyökérobjektumtól öröklődik (C# esetén az osztályból Object). A Java -nak számos primitív típusa van, amelyek nem objektumok. Ezek mellett a Java wrapper objektumtípusokat is biztosít, így a fejlesztő saját belátása szerint használhatja a primitív vagy objektumtípusokat.

Típuskompatibilitás

A típuskonzisztencia-ellenőrző mechanizmus egy statikusan beírt nyelvben ellenőrzi, hogy bármely kifejezés megfelel-e a kontextus által elvárt típusnak, amelyben előfordul. Például egy típus- hozzárendelési utasításban a kifejezéshez kikövetkeztetett típusnak meg kell egyeznie a változóhoz deklarált vagy kikövetkeztetett típussal . A megfelelőségi jelölés, az úgynevezett kompatibilitás , minden nyelvre jellemző. x := eex

Ha a eés xazonos típusúak, és ehhez a típushoz engedélyezett a hozzárendelés, akkor a kifejezés legális. Ezért a legegyszerűbb típusú rendszerekben a két típus kompatibilitásának kérdése leegyszerűsödik egyenlőségük ( ekvivalenciájuk ) kérdésére. A különböző nyelvek azonban eltérő kritériumokkal rendelkeznek a két kifejezés típuskompatibilitásának meghatározására. Ezek az ekvivalenciaelméletek két véglet között változnak: strukturális típusú rendszerek , amelyekben két típus ekvivalens, ha egy érték ugyanazt a belső szerkezetét írják le; és nominatív típusú rendszerek , amelyekben a szintaktikailag különböző típusok soha nem ekvivalensek ( vagyis két típus csak akkor egyenlő, ha az azonosítóik azonosak) .  

altípusú nyelveken a kompatibilitási szabályok bonyolultabbak. Például, ha egy altípusa , akkor a típus értéke használható olyan környezetben, amely típus értéket vár , még akkor is, ha ennek ellenkezője nem igaz. Az ekvivalenciához hasonlóan az altípus-kapcsolatok nyelvenként változnak, és a szabályoknak számos változata lehetséges. A paraméteres vagy szituációs polimorfizmus jelenléte egy nyelvben szintén befolyásolhatja a típuskompatibilitást. ABAB

Befolyás a programozási stílusra

Egyes programozók a statikus típusú rendszereket részesítik előnyben, mások a dinamikus rendszereket . A statikusan beírt nyelvek jeltípus-konzisztencia-hibák fordítási időben , hatékonyabban futtatható kódot generálhatnak, és az ilyen nyelvek esetében megvalósítható a relevánsabb befejezés az IDE- ben . A dinamikus gépelés hívei azzal érvelnek, hogy ezek alkalmasabbak a gyors prototípuskészítésre , és hogy a típusillesztési hibák csak töredékét képezik a programok lehetséges hibáinak [9] [10] . Másrészt a statikusan beírt nyelvekben általában nincs szükség explicit típusdeklarációra, ha a nyelv támogatja a típuskövetkeztetést , és egyes dinamikusan tipizált nyelvek futásidejű optimalizálást hajtanak végre [11] [12] , gyakran részleges típus használatával. következtetés [13] .

Lásd még

Jegyzetek

  1. Cardelli, 2004 , p. egy.
  2. Pierce, 2002 , p. egy.
  3. 12 Pierce , 2002 , p. 208.
  4. 1 2 3 Andrew Cooke. Bevezetés a számítógépes nyelvekbe (hivatkozás nem érhető el ) Letöltve: 2012. július 13. Az eredetiből archiválva : 2012. augusztus 15. 
  5. Mitchell, Plotkin, 1988 .
  6. Egzisztenciális típusok a HaskellWikin . Letöltve: 2014. július 15. Az eredetiből archiválva : 2014. július 20.
  7. Típusindexelt értékek . Letöltve: 2014. július 15. Az eredetiből archiválva : 2016. április 21..
  8. Szabvány ECMA-334 Archiválva : 2010. október 31. a Wayback Machine -nél , 8.2.4 Típusrendszer-egyesítés.
  9. Meijer, Drayton .
  10. Amanda Laucher, Paul Snively. Típusok vs  tesztek . InfoQ. Letöltve: 2014. február 26. Az eredetiből archiválva : 2014. március 2..
  11. Az Adobe és a Mozilla Foundation a nyílt forráskódú Flash Player Scripting Engine-hez . Letöltve: 2014. február 26. Az eredetiből archiválva : 2010. október 21..
  12. Psyco, a Pythonra specializálódott fordítóprogram . Letöltve: 2014. február 26. Az eredetiből archiválva : 2019. november 29.
  13. C-Extensions for Python Archiválva : 2007. augusztus 11. a Wayback Machine -nél . Cython (2013-05-11). Letöltve: 2013-07-17

Irodalom

Linkek