Система структурных типов
Эта статья нуждается в дополнительных ссылок для проверки . ( июль 2011 г. ) |
Типовые системы |
---|
Общие понятия |
Основные категории |
Второстепенные категории |
Система структурных типов (или система типов на основе свойств ) — это основной класс систем типов , в которых совместимость и эквивалентность типов определяются фактической структурой или определением типа, а не другими характеристиками, такими как его имя или место объявления. Структурные системы используются для определения того, эквивалентны ли типы и является ли тип подтипом другого. Это контрастирует с номинативными системами , где сравнения основаны на именах типов или явных объявлениях, и с утиной типизацией , в которой на совместимость проверяется только часть структуры, к которой осуществляется доступ во время выполнения.
Описание [ править ]
При структурной типизации элемент считается совместимым с другим, если для каждого признака типа второго элемента существует соответствующий и идентичный признак в типе первого элемента. На некоторых языках могут отличаться детали, например, должны ли функции совпадать по названию. Это определение не является симметричным и включает совместимость подтипов. Два типа считаются идентичными, если каждый из них совместим с другим.
Например, OCaml использует структурную типизацию в методах для совместимости типов объектов. Go использует структурную типизацию методов для определения совместимости типа с интерфейсом. Шаблонные функции C++ демонстрируют структурную типизацию аргументов типа. Haxe использует структурную типизацию, но классы не имеют структурных подтипов.
В языках, поддерживающих полиморфизм подтипов , аналогичная дихотомия может быть сформирована на основе того, как определяется связь подтипов. Один тип является подтипом другого тогда и только тогда, когда он содержит все признаки базового типа или его подтипов. Подтип может содержать дополнительные функции, например элементы, отсутствующие в базовом типе, или более сильные инварианты.
Существует различие между структурной заменой предполагаемого и непредполагаемого полиморфизма. Некоторые языки, такие как Haskell , не заменяют структурно в случае, когда ожидаемый тип объявлен (т. е. не выводится), например, заменяют только функции, которые являются полиморфными на основе сигнатур посредством вывода типа. [1] Тогда невозможно случайно создать подтип невыведенного типа, хотя все же можно обеспечить явное преобразование в невыведенный тип, который вызывается неявно.
Структурное подтипирование, возможно, более гибкое, чем номинативное подтипирование , поскольку оно позволяет создавать специальные типы и протоколы ; в частности, он позволяет создавать тип, который является супертипом существующего типа, без изменения определения последнего. Однако это может быть нежелательно, если программист желает создать закрытые абстракции.
Ошибка структурной типизации по сравнению с номинативной типизацией заключается в том, что два отдельно определенных типа, предназначенных для разных целей, но случайно обладающих одинаковыми свойствами (например, оба состоят из пары целых чисел), могут рассматриваться системой типов как один и тот же тип просто потому, что они имеют идентичную структуру. Один из способов избежать этого — создать один алгебраический тип данных для каждого использования.
В 1990 году Кук и др. доказали, что наследование не является подтипированием в структурно-типизированных объектно-ориентированных языках. [2]
Проверка совместимости двух типов на основе структурной типизации является нетривиальной операцией, например, требует сохранения стека ранее проверенных типов. [3]
Пример [ править ]
Объекты в OCaml структурно типизированы по именам и типам их методов.
Объекты можно создавать напрямую ( непосредственные объекты ), минуя именительный класс. Классы служат только функциями для создания объектов.
# let x =
object
val mutable x = 5
метод get_x = x
метод 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 =
объекта
метод get_x = 2
метод set_x y = Printf . printf "%d \n " y
end ;;
val y : < get_x : int ; set_x : int -> unit > = < obj >
OCaml считает их однотипными. Например, оператор равенства принимает только два значения одного типа:
# х = у ;;
- : bool = ложь
Таким образом, они должны быть одного типа, иначе это даже не будет проверять тип. Это показывает, что эквивалентность типов носит структурный характер.
Можно определить функцию, которая вызывает метод:
# let set_to_10 a = a # set_x 10 ;;
val set_to_10 : < set_x : int -> ' a ; .. > -> ' a = < весело >
Выведенный тип для первого аргумента ( < set_x : int -> 'a; .. >
) Интересно. ..
означает, что первым аргументом может быть любой объект, имеющий метод «set_x», который принимает в качестве аргумента целое число.
Поэтому его можно использовать на объекте x
:
# set_to_10 x ;;
- : единица = ()
Можно создать другой объект, который будет иметь этот метод и тип метода; остальные методы не имеют значения:
# let z =
объекта
метод blahblah = 2 . 5
метод set_x y = Printf . printf "%d \n " y
end ;;
val z : < блабла : float ; set_x : int -> unit > = < obj >
На нем также работает функция set_to_10:
# set_to_10 z ;;
10
- : единица = ()
Это показывает, что совместимость таких вещей, как вызов метода, определяется структурой.
Давайте определим синоним типа для объектов, имеющих только метод get_x и никаких других методов:
# введите 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 ;;
- : целое = 10
Но не возражать z
, поскольку это не структурный подтип:
# (z :> simpler_obj);; Это выражение нельзя привести к типу simpler_obj = < get_x : int >; он имеет тип < blahblah: float; set_x : int -> unit > но здесь используется с типом < get_x: интервал; .. > Первый тип объекта не имеет метода 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 .