Моцная і слабая тыпізацыя

клясыфікацыя сыстэм тыпу мовы праграмаваньня паводле таго, наколькі моцна яны гарантуюць сапраўднасьць праграмы

Адным з варыянтаў умоўнай клясыфікацыі моў праграмаваньня ў машынным праграмаваньні зьяўляецца разьмеркаваньне іх паводле таго, моцна ці слаба тыпізаванымі робіць іх сыстэма тыпаў. Аднак дакладнага тэхнічнага вызначэньня гэтых тэрмінаў няма — адсюль і спрэчкі наконт адноснага ранжыраваньня «моцы» сыстэм тыпаў.[1] З-за чаго часта пазьбягаюць выразаў «моцная тыпізацыя» і «слабая тыпізацыя» на карысць канкрэтных тэрмінаў, такіх як «бясьпека тыпаў».

Як правіла, мова з моцнай тыпізацыяй мае больш строгія правілы тыпізацыі падчас кампіляцыі — памылкі і выключэньні часцей узнікаюць падчас кампіляцыі. Большасць з гэтых правілаў уплываюць на прызначэньне зьменных, вяртаемыя функцыямі значэньні, аргумэнты працэдур і выклікі функцый. Мовы з дынамічнай тыпізацыяй (дзе праверка тыпаў адбываецца падчас выкананьня) таксама могуць быць моцна тыпізаванымі. У дынамічна тыпізаваных мовах значэньні, а не зьменныя, маюць тыпы.

Слаба тыпізаваная мова мае больш свабодныя правілы вызначэньня тыпаў — звычайна, няяўнае пераўтварэнне тыпаў адбываецца падчас выкананьня. Часта гэта можа даць непрадказальныя вынікі, ці нават прывесьці да памылкі.[2] Іншай роднаснай канцэпцыяй да слабае тыпізацыі зьяўляецца — лятэнтная тыпізацыя.

Гісторыя

рэдагаваць

У 1974 годзе Барбара Ліскоў і Стывен Зіл вызначылі строга тыпізаваную мову як мову, у якой «кожны раз, калі аб’ект перадаецца ад зрабіўшае выклік функцыі да выкліканай функцыі, яго тып павінен быць сумяшчальны з тыпам, аб’яўленым у выкліканай функцыі».[3] У 1977 г. К. Джэксан пісаў: «У моцна тыпізаванай мове кожная вобласць даных мае свой тып, і кожны зварот да яе выконвае патрабаваньні гэтых тыпаў».[4]

Вызначэньне «моцы» тыпізацыі

рэдагаваць

Для клясыфікацыі мовы як «моцна» ці «слаба» тыпізаванай зьвяртаюць увагу на такіх яе характарыстыкі як: бясьпека тыпаў, бясьпека памяці, статычная або дынамічная праверка тыпаў.

Тыпы даных пры «моцнай тыпізацыі» звычайна выкарыстоўваюцца для забясьпячэньня карэктнасьці кода і вылучэньня некаторых клясаў памылак праграмаваньня.

Пераўтварэньне тыпаў

рэдагаваць

Некаторыя мовы праграмаваньня дазваляюць выкарыстоўваць значэньне аднаго тыпу ў якасьці значэння іншага тыпу. Часам гэта вызначаюць як «слабая тыпізацыя».

Напрыклад, Ааз Марух заўважае: «Прымусовае ўжываньне значэньня аднаго тыпу ў якасьці значэньня іншага тыпу, якое магчымае ў некаторых мовах са статычнай тыпізацыяй, дзякуючы іх пэўным сынтаксычным асаблівасьцям (разгледзім звычайнае выкарыстанне void* у C), — звычайная прыкмета слабай тыпізацыі.»[5]

Іншы прыклад, GCC апісвае гэта як «жангліраваньне тыпамі» і папярэджвае, што гэта парушае строгую адрасацыю. Т’яга Мас’эйра абмяркоўвае некалькі праблемаў, якія могуць узьнікнуць, калі «жангліраваньне тыпамі» прымушае кампілятар рабіць недарэчныя аптымізацыі.[6]

Шмат моў дазваляюць зьдзяйсьняць пераўтварэньне тыпаў бясьпечным для тыпу спосабам. Напрыклад, як C++, так і C# дазваляюць праграмам вызначаць апэратары для пераўтварэння значэння з аднаго тыпу ў іншы з дакладна вызначанай сэмантыкай. Калі кампілятар C++ сутыкаецца з такім пераўтварэннем, ён разглядае апэрацыю як выклік функцыі. Наадварот, пераўтварэньне значэння ў тып void* у C  - небяспечная аперацыя, нябачная для кампілятара.

Указальнікі

рэдагаваць

Некаторыя мовы праграмаваньня даюць магчымасьць працаваць з указальнікі як зь лікавыя значэньнямі й выконваць над імі арытметычныя апэрацыі. Гэтыя мовы часам называюць «слаба тыпізаванымі», паколькі арытметыка паказальнікаў можа выкарыстоўвацца для абыходу сістэмы тыпаў мовы.

Бязтэгавыя аб’яднаньні

рэдагаваць

Некаторыя мовы праграмаваньня падтрымліваюць бязтэгавыя аб’яднаньні, якія дазваляюць разглядаць значэньне аднаго тыпу як значэньне іншага тыпу.

Статычная праверка тыпу

рэдагаваць

У артыкуле «Typeful Programming»[7] Лукі Кардэлі «моцная сыстэма тыпаў» апісваецца як сыстэма, у якой няма магчымасьці неправеранай памылкі тыпу падчас выкананьня. У іншай крыніцы адсутнасьць неправераных памылак падчас выкананьня называецца бясьпекай або бясьпекай тыпаў.

Варыяцыі паміж мовамі праграмаваньня

рэдагаваць

Некаторыя з вышэй прыведзеных вызначэньняў супярэчлівыя, другія разьняцца канцэптуальна, а трэція з’яўляюцца прыватнымі выпадкамі (з дадатковымі абмежаваньнямі) іншых, больш «ліберальных» (менш строгіх) вызначэньняў. Вялікае разыходжаньне паміж гэтымі вызначэньнямі дае прастору для абароны сцьвярджэньняў адносна большасьці моў праграмавання, што яны альбо моцна, альбо слаба тыпізаваныя. Напрыклад:

  • Java, Pascal, Ada і C патрабуюць, каб зьменныя яўна аб’яўлялі тып, і падтрымліваюць яўнае пераўтварэньне паміж лічбавымі тыпамі. Часам кажуць, што Java, C#, Ada і Pascal маюць мацнейшую за C тыпізацыю, таму што C падтрымлівае больш відаў няяўных пераўтварэньняў і дазваляе яўнае прывядзеньне указальнікаў, у той час як Java і Pascal гэтага не падтрымліваюць. Java можа лічыцца больш моцна тыпізаванай за Pascal, паколькі сыстэма тыпаў Java кантралююцца сыстэмай тыпаў віртуальнай машыны Java. C# і VB.NET падобныя на Java у гэтым, хоць яны дазваляюць адключыць дынамічную праверку тыпаў шляхам відавочнага размяшчэньня сэгмэнтаў коду ў «небяспечным кантэксьце». Сыстэма тыпаў Pascal адзначаецца як «занадта моцная», таму што памер масіва або радка з’яўляецца часткай яго тыпу, што робіць некаторыя задачы праграмаваньня вельмі складанымі. Аднак Delphi выпраўляе гэтую праблему.[8][9]
  • Smalltalk, Ruby, Python і Self — усе «моцна тыпізаваныя» ў тым сэнсе, што памылкі тыпаў прадухіляюцца падчас выкананьня і яны практычна не робяць няяўнага пераўтварэння тыпаў, але гэтыя мовы не выкарыстоўваюць статычную праверку тыпаў. Тэрмін «качыная тыпізацыя» цяпер выкарыстоўваецца для апісання парадыгмы дынамічнай тыпізацыі, якая выкарыстоўваецца ў мовах гэтай групы.
  • Усе мовы сямейства Lisp «строга тыпізаваныя» ў тым сэнсе, што памылкі тыпаў прадухіляюцца падчас выкананьня. Некаторыя дыялекты Lisp, такія як Common Lisp або Clojure, сапраўды падтрымліваюць розныя формы дэклярацый тыпаў,[10] а некаторыя кампілятары (CMU Common Lisp (CMUCL)[11] і звязаныя з імі) выкарыстоўваюць гэтыя дэклярацыі разам з вывадам тыпаў, каб уключыць розныя аптымізацыі і праверкі тыпаў пад час кампіляцыі.
  • Standard ML, F#, OCaml, Haskell, Go і Rust — статычна тыпізаваныя, але кампілятар аўтаматычна выводзіць дакладны тып для большасьці значэньняў.
  • Асэмблер і Forth можна ахарактарызаваць як нетыпізаваныя. Так як праверкі тыпу няма зусім, гэта абавязак праграміста, каб пераканацца, што функцыі выклікаюцца з данымі належнага тыпу.