Система структурных типов
Эта статья нуждается в дополнительных цитатах для проверки . ( июль 2011 г. ) |
Типовые системы |
---|
Общие понятия |
Основные категории |
Второстепенные категории |
Система структурных типов (или система типов на основе свойств ) — это основной класс систем типов , в которых совместимость и эквивалентность типов определяются фактической структурой или определением типа, а не другими характеристиками, такими как его имя или место объявления. Структурные системы используются для определения того, эквивалентны ли типы и является ли тип подтипом другого. Это контрастирует с номинативными системами , где сравнения основаны на именах типов или явных объявлениях, и с утиной типизацией , в которой на совместимость проверяется только часть структуры, к которой осуществляется доступ во время выполнения.
Описание [ править ]
При структурной типизации элемент считается совместимым с другим, если для каждого признака типа второго элемента существует соответствующий и идентичный признак в типе первого элемента. На некоторых языках могут отличаться детали, например, должны ли функции совпадать по названию. Это определение не является симметричным и включает совместимость подтипов. Два типа считаются идентичными, если каждый из них совместим с другим.
Например, OCaml использует структурную типизацию в методах для совместимости типов объектов. Go использует структурную типизацию методов для определения совместимости типа с интерфейсом. Функции шаблонов C++ демонстрируют структурную типизацию аргументов типа. Haxe использует структурную типизацию, но классы не имеют структурных подтипов.
В языках, поддерживающих полиморфизм подтипов , аналогичная дихотомия может быть сформирована на основе того, как определяется связь подтипов. Один тип является подтипом другого тогда и только тогда, когда он содержит все признаки базового типа или его подтипов. Подтип может содержать дополнительные функции, например элементы, отсутствующие в базовом типе, или более сильные инварианты.
Существует различие между структурной заменой предполагаемого и непредполагаемого полиморфизма. Некоторые языки, такие как Haskell , не заменяют структурно в случае, когда ожидаемый тип объявлен (т. е. не выводится), например, заменяют только функции, которые являются полиморфными на основе сигнатур посредством вывода типа. [1] Тогда невозможно случайно создать подтип невыведенного типа, хотя все же можно обеспечить явное преобразование в невыведенный тип, который вызывается неявно.
Структурное подтипирование, возможно, более гибкое, чем номинативное подтипирование , поскольку оно позволяет создавать специальные типы и протоколы ; в частности, он позволяет создавать тип, который является супертипом существующего типа, без изменения определения последнего. Однако это может быть нежелательно, если программист хочет создать закрытые абстракции.
Ошибка структурной типизации по сравнению с номинативной типизацией заключается в том, что два отдельно определенных типа, предназначенных для разных целей, но случайно обладающих одинаковыми свойствами (например, оба состоят из пары целых чисел), могут рассматриваться системой типов как один и тот же тип просто потому, что они имеют идентичную структуру. Один из способов избежать этого — создать один алгебраический тип данных для каждого использования.
В 1990 году Кук и др. доказали, что наследование не является подтипированием в структурно-типизированных объектно-ориентированных языках. [2]
Проверка совместимости двух типов на основе структурной типизации является нетривиальной операцией, например, требует сохранения стека ранее проверенных типов. [3]
Пример [ править ]
Объекты в OCaml структурно типизированы по именам и типам их методов.
Объекты можно создавать напрямую ( непосредственные объекты ), минуя именительный класс. Классы служат только функциями для создания объектов.
# let x =
object
val mutable x = 5
method get_x = x
method set_x y = x <- y
end;;
val x : < get_x : int; set_x : int -> unit > = <obj>
Здесь интерактивная среда выполнения OCaml для удобства распечатывает предполагаемый тип объекта. Его тип ( < get_x : int; set_x : int -> unit >
) определяется только своими методами. Другими словами, тип x определяется типами методов «get_x: int» и «set_x: int -> unit», а не каким-либо именем. [4]
Чтобы определить другой объект, который имеет те же методы и типы методов:
# 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 > = <obj>
OCaml считает их однотипными. Например, оператор равенства принимает только два значения одного типа:
# x = y;;
- : bool = false
Таким образом, они должны быть одного типа, иначе это даже не будет проверять тип. Это показывает, что эквивалентность типов носит структурный характер.
Можно определить функцию, которая вызывает метод:
# let set_to_10 a = a#set_x 10;;
val set_to_10 : < set_x : int -> 'a; .. > -> 'a = <fun>
Выведенный тип для первого аргумента ( < set_x : int -> 'a; .. >
) интересно. ..
означает, что первым аргументом может быть любой объект, имеющий метод «set_x», который принимает в качестве аргумента целое число.
Поэтому его можно использовать на объекте x
:
# set_to_10 x;;
- : unit = ()
Можно создать другой объект, который будет иметь этот метод и тип метода; остальные методы не имеют значения:
# let z =
object
method blahblah = 2.5
method set_x y = Printf.printf "%d\n" y
end;;
val z : < blahblah : float; set_x : int -> unit > = <obj>
На нем также работает функция set_to_10:
# set_to_10 z;;
10
- : unit = ()
Это показывает, что совместимость таких вещей, как вызов метода, определяется структурой.
Давайте определим синоним типа для объектов, имеющих только метод get_x и никаких других методов:
# type simpler_obj = < get_x : int >;;
type 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);; This expression cannot be coerced to type simpler_obj = < get_x : int >; it has type < blahblah : float; set_x : int -> unit > but is here used with type < get_x : int; .. > The first object type has no method get_x
Это показывает, что совместимость расширяющихся принуждений носит структурный характер.
Ссылки [ править ]
- ^ «Полиморфизм на основе сигнатур» .
- ^ Кук, WR; Хилл, WL; Каннинг, PS (январь 1990 г.). «Наследование — это не подтип». Материалы 17-го симпозиума ACM SIGPLAN-SIGACT по принципам языков программирования - POPL '90 . Сан-Франциско, Калифорния. стр. 125–135. дои : 10.1145/96709.96721 . ISBN 978-0897913430 . S2CID 8225906 .
{{cite book}}
: CS1 maint: отсутствует местоположение издателя ( ссылка ) - ^ «Совместимость типов: имя против структурной эквивалентности» .
- ^ «Типы объектов» .
- Пирс, Бенджамин К. (2002). «19,3». Типы и языки программирования . МТИ Пресс. ISBN 978-0-262-16209-8 .