Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

Система структурных типов (или система типов на основе свойств ) - это основной класс систем типов, в которых совместимость и эквивалентность типов определяются фактической структурой или определением типа, а не другими характеристиками, такими как его имя или место объявления. Структурные системы используются, чтобы определить, эквивалентны ли типы и является ли тип подтипом другого. Это контрастирует с номинативными системами , где сравнения основаны на именах типов или явных объявлениях, и с утиной типизацией , в которой только часть структуры, к которой осуществляется доступ во время выполнения, проверяется на совместимость.

Описание [ править ]

При структурной типизации элемент считается совместимым с другим, если для каждой функции в типе второго элемента имеется соответствующая и идентичная функция в первом типе элемента. Некоторые языки могут отличаться по деталям, например, должны ли функции совпадать по названию. Это определение не является симметричным и включает совместимость подтипов. Два типа считаются идентичными, если каждый совместим с другим.

Например, OCaml использует структурную типизацию для методов совместимости типов объектов. Go использует структурную типизацию методов для определения совместимости типа с интерфейсом. Функции шаблонов C ++ демонстрируют структурную типизацию аргументов типа. Haxe использует структурную типизацию, но классы не имеют структурных подтипов.

В языках, которые поддерживают полиморфизм подтипов , подобная дихотомия может быть сформирована на основе того, как определяется отношение подтипов. Один тип является подтипом другого тогда и только тогда, когда он содержит все функции базового типа или его подтипов. Подтип может содержать добавленные функции, такие как элементы, отсутствующие в базовом типе, или более сильные инварианты.

Существует различие между структурной заменой предполагаемого и не предполагаемого полиморфизма. Некоторые языки, такие как Haskell , не выполняют структурную замену в случае, когда ожидаемый тип объявлен (т. Е. Не выведен), например, только заменяют функции, которые являются полиморфными на основе сигнатур посредством вывода типа. [1] Тогда невозможно случайно подтипировать невыявленный тип, хотя все еще может быть возможно обеспечить явное преобразование в невыведенный тип, который вызывается неявно.

Структурное подтипирование, возможно, более гибкое, чем номинативное подтипирование , поскольку оно позволяет создавать специальные типы и протоколы ; в частности, он позволяет создавать тип, который является супертипом существующего типа, без изменения определения последнего. Однако это может быть нежелательно, если программист хочет создавать закрытые абстракции.

Ошибка структурной типизации по сравнению с номинативной типизацией заключается в том, что два отдельно определенных типа, предназначенные для разных целей, но случайно обладающие одинаковыми свойствами (например, оба состоят из пары целых чисел), могут считаться системой типов одним и тем же типом просто потому, что они имеют идентичную структуру. Один из способов избежать этого - создать один алгебраический тип данных для каждого использования.

В 1990 году Кук и др. Доказали, что наследование не является подтипом в объектно-ориентированных языках с структурной типизацией. [2]

Пример [ править ]

Объекты в OCaml структурно типизированы по именам и типам их методов.

Объекты могут быть созданы напрямую ( непосредственные объекты ), не проходя через номинативный класс. Классы служат только как функции для создания объектов.

 #  let  x  =  object  val  mutable  x  =  5  method  get_x  =  x  method  set_x  y  =  x  <-  y  end ;; значение x : < get_x : int ; set_x : int -> unit > = < объект >               

Здесь интерактивная среда выполнения OCaml для удобства распечатывает предполагаемый тип объекта. Его type ( < get_x : int; set_x : int -> unit >) определяется только его методами. Другими словами, тип x определяется типами методов «get_x: int» и «set_x: int -> unit», а не каким-либо именем. [3]

Чтобы определить другой объект, который имеет те же методы и типы методов:

 #  let  y  =  object  method  get_x  =  2  method  set_x  y  =  Printf . printf  "% d \ n "  y  end ;; val y : < get_x : int ; set_x : int -> unit > = < объект >               

OCaml считает их однотипными. Например, оператор равенства набирается так, чтобы принимать только два значения одного типа:

 #  x  =  y ;; - : bool = false     

Значит, они должны быть одного типа, иначе это даже не проверка типа. Это показывает, что эквивалентность типов структурна.

Можно определить функцию, вызывающую метод:

 #  let  set_to_10  a  =  a # set_x  10 ;; значение set_to_10 : < set_x : int -> ' a ; .. > -> ' a = < веселье >               

Выведенный тип для первого аргумента ( < set_x : int -> 'a; .. >) интересен. Это ..означает, что первым аргументом может быть любой объект, у которого есть метод "set_x", который принимает в качестве аргумента int.

Таким образом, его можно использовать на объекте x:

 #  set_to_10  x ;; - : unit = ()     

Можно создать другой объект, который имеет этот метод и тип метода; остальные методы не имеют значения:

 #  let  z  =  object  method  blahblah  =  2 . 5  метод  set_x  y  =  Printf . printf  "% d \ n "  y  end ;; val z : < blahblah : float ; set_x : int -> unit > = < объект >               

С ним также работает функция "set_to_10":

 #  set_to_10  z ;;  10  -  :  единица  =  ()

Это показывает, что совместимость таких вещей, как вызов метода, определяется структурой.

Давайте определим синоним типа для объектов только с помощью метода get_x и без других методов:

 #  type  simpler_obj  =  <  get_x  :  int  > ;; введите simpler_obj = < get_x : int >        

Объект xне этого типа; но структурно xотносится к подтипу этого типа, поскольку xсодержит надмножество его методов. Так xможно принуждать к этому типу:

 #  ( x  :>  simpler_obj ) ;; - : simpler_obj = < obj > # ( x :> simpler_obj ) # get_x ;; - : int = 10              

Но не объект z, потому что это не структурный подтип:

# (z:> simpler_obj) ;;Это выражение нельзя заставить ввести simpler_obj = <get_x: int>;он имеет тип <blahblah: float; set_x: int -> unit> но здесь используется с типом <get_x: int; ..>Первый тип объекта не имеет метода get_x

Это показывает, что совместимость для расширяющихся принуждений носит структурный характер.

Ссылки [ править ]

  1. ^ "Полиморфизм на основе подписи" .
  2. ^ Кук, WR; Hill, WL; Консервирование, PS (январь 1990 г.). «Наследование - это не подтип» . Материалы семнадцатого ежегодного симпозиума ACM по принципам языков программирования . Сан-Франциско, Калифорния: 125–135. DOI : 10.1145 / 96709.96721 . ISBN 978-0897913430.
  3. ^ «Типы объектов» .
  • Пирс, Бенджамин С. (2002). «19,3». Типы и языки программирования . MIT Press. ISBN 978-0-262-16209-8.

Внешние ссылки [ править ]

  • NominativeAndStructuralTyping в WikiWikiWeb