Структурная типизация: определение, отличия от номинативной и утиной типизации. Совместимость типов определяется структурой, а не именем. Языки программирования.
Сравнивайте с английским: нажмите на абзац — оригинал откроется в окне. Кнопка EN под абзацем показывает его прямо в тексте.
Введение
Класс типовых систем
Class of type systems
Структурная система типов (или система типов, основанная на свойствах) — это основной класс типовых систем, в котором совместимость и эквивалентность типов определяются фактической структурой или определением типа, а не другими характеристиками, такими как его имя или место объявления. Структурные системы используются для определения эквивалентности типов и проверки, является ли один тип подтипом другого. Она противопоставляется номинативным системам, где сравнения основаны на именах типов или явных объявлениях, и динамической типизации (Duck typing), в которой совместимость проверяется только для той части структуры, которая используется во время выполнения.
A structural type system (or property based type system) is a major class of type systems in which type compatibility and equivalence are determined by the type's actual structure or definition and not by other characteristics such as its name or place of declaration. Structural systems are used to determine if types are equivalent and whether a type is a subtype of another. It contrasts with nominative systems, where comparisons are based on the names of the types or explicit declarations, and duck typing, in which only the part of the structure accessed at runtime is checked for compatibility.
Описание
В структурной типизации элемент считается совместимым с другим, если для каждой характеристики в типе второго элемента существует соответствующая и идентичная характеристика в типе первого элемента. В некоторых языках детали могут различаться, например, требуется ли совпадение имён характеристик. Это определение несимметрично и включает совместимость подтипов. Два типа считаются идентичными, если каждый из них совместим с другим. Например, OCaml использует структурную типизацию методов для обеспечения совместимости типов объектов. Go использует структурную типизацию методов для определения совместимости типа с интерфейсом. Функции шаблонов C++ демонстрируют структурную типизацию аргументов типов. Haxe использует структурную типизацию, но классы не поддерживают структурное подтипирование. В языках, поддерживающих полиморфизм подтипов, можно сформировать аналогичное разделение в зависимости от способа определения отношения подтипа. Один тип является подтипом другого тогда и только тогда, когда он содержит все характеристики базового типа или его подтипов. Подтип может содержать дополнительные характеристики, такие как члены, отсутствующие в базовом типе, или более строгие инварианты. Существует различие между структурной подстановкой для выведенного и невыведенного полиморфизма. Некоторые языки, такие как Haskell, не выполняют структурную подстановку в случае, когда ожидаемый тип объявлен (т.е. не выведен), например, подстановка выполняется только для функций, полиморфных на основе сигнатуры посредством вывода типов. Тогда невозможно случайно подтипировать невыведенный тип, хотя всё ещё можно обеспечить явное преобразование к невыведенному типу, которое вызывается неявно. Структурное подтипирование, вероятно, более гибкое, чем номинативное подтипирование, поскольку оно позволяет создавать ad hoc типы и протоколы; в частности, оно позволяет создать тип, являющийся супертипом существующего типа, не изменяя определение последнего. Однако это может быть нежелательно, если программист стремится создавать закрытые абстракции. Опасность структурной типизации по сравнению с номинативной заключается в том, что два независимо определенных типа, предназначенных для разных целей, но случайно обладающих одинаковыми свойствами (например, оба состоящие из пары целых чисел), могут быть признаны одним и тем же типом системой типов, просто потому, что они имеют идентичную структуру. Одним из способов избежать этого является создание отдельного алгебраического типа данных для каждого варианта использования. В 1990 году Кук и др. доказали, что наследование не является подтипированием в объектно-ориентированных языках со структурной типизацией. Проверка совместимости двух типов на основе структурной типизации — нетривиальная операция, например, требующая ведения стека ранее проверенных типов.
In structural typing, an element is considered to be compatible with another if, for each feature within the second element's type, a corresponding and identical feature exists in the first element's type. Some languages may differ on the details, such as whether the features must match in name. This definition is not symmetric, and includes subtype compatibility. Two types are considered to be identical if each is compatible with the other. For example, OCaml uses structural typing on methods for compatibility of object types. Go uses structural typing on methods to determine compatibility of a type with an interface. C++ template functions exhibit structural typing on type arguments. Haxe uses structural typing, but classes are not structurally subtyped. In languages which support subtype polymorphism, a similar dichotomy can be formed based on how the subtype relationship is defined. One type is a subtype of another if and only if it contains all the features of the base type, or subtypes thereof. The subtype may contain added features, such as members not present in the base type, or stronger invariants. A distinction exists between structural substitution for inferred and non inferred polymorphism. Some languages, such as Haskell, do not substitute structurally in the case where an expected type is declared (i. e., not inferred), e. g., only substitute for functions that are signature based polymorphic via type inference. Then it is not possible to accidentally subtype a non inferred type, although it may still be possible to provide an explicit conversion to a non inferred type, which is invoked implicitly. Structural subtyping is arguably more flexible than nominative subtyping, as it permits the creation of ad hoc types and protocols; in particular, it permits creation of a type which is a supertype of an existing type, without modifying the definition of the latter. However, this may not be desirable where the programmer wishes to create closed abstractions. A pitfall of structural typing versus nominative typing is that two separately defined types intended for different purposes, but accidentally holding the same properties (e. g. both composed of a pair of integers), could be considered the same type by the type system, simply because they happen to have identical structure. One way this can be avoided is by creating one algebraic data type for each use. In 1990, Cook, et al., proved that inheritance is not subtyping in structurally typed OO languages. Checking that two types are compatible, based on structural typing, is a non trivial operation, e. g., requires maintaining a stack of previous checked types.