====== Система типов ====== Совокупность правил для семантического анализатора языка, определяющая свойства данных, которыми оперирует программа. Типом называется атрибут, которым помечается конструкция языка (переменная, выражение, аргумент и возвращаемое значение функции и т.д.) и который определяет набор операций, применимых к этой конструкции. Например, арифметический оператор деления (/) применим к переменной числового типа, но неприменим к переменной строкового типа. ===== Статическая и динамическая типизация ===== Язык программирования, требующий явного указания типов в программе, называется **статически типизированным**. В таких языках переменные не могут менять свой тип во время выполнения программы. Языки, в которых тип переменных может меняться во время выполнения, называются **динамически типизированными**. Динамическая типизация упрощает реализацию некоторых алгоритмов, но по эффективности значительно уступает статической. К тому же, благодаря статической типизации компилятор может осуществить формальный семантический анализ программы перед ее трансляцией - то есть, проверить, не содержит ли программа некорректные или противоречивые операции. В динамически типизированном языке некорректные операции отлавливаются во время выполнения, что может усложнить отладку. Принято считать, что статическая типизация лучше всего подходит для крупных проектов со сложными моделями данных, а динамическая - для коротких программ и скриптов. Примеры статически типизированных языков: C, C++, Pascal, BASIC, Java, C#, D, Go, Rust, Fortran, Haskell, ML. Примеры динамически типизированных языков: Perl, Python, Ruby, PHP, JavaScript, Smalltalk. ===== Примитивные и составные типы ===== **Примитивный** или **простой тип** является встроенным типом языка. К таким типам относят, в первую очередь, алгебраические типы: целочисленный (integer), вещественный (real), символьный (char), логический (boolean). Характерной особенностью алгебраических типов является фиксированная длина - чаще всего 8, 16, 32 и 64 бит. В некоторых языках строковой тип (string) также является примитивным (в C-подобных языках строковой тип является разновидностью массива). Также некоторые языки расширяют этот набор более сложными математическими объектами - такими как вектор, матрица, комплексное число и т.д. Примитивным типом также является [[указатель]], использующийся для хранения адресов ячеек памяти. **Составной** или **сложный тип** - это тип, определяемый пользователем. Простейшими составными типами являются массив и структура. * **Массив** (array) - это упорядоченный набор однотипных значений (элементов), доступ к которым осуществляется по целочисленному индексу * **Структура** (structure) - упорядоченный набор разнотипных значений (полей), доступ к которым осуществляется по именам. В некоторых языках также поддерживаются следующие составные типы: * **Класс** (class) - образец для создания объектов. Подобен структуре, но, помимо полей, может содержать **методы** - функции, сопоставленные с объектом. Классы поддерживают [[полиморфизм]] и [[наследование]] * **Интерфейс** (interface) - разновидность [[контракт|контракта]], гарантирующая доступ к определенным методам без привязки к конкретному классу. Переменные интерфейсного типа могут хранить любые объекты, реализующие этот интерфейс * **Перечисление** (enumeration) - тип, принимающий значение из определенного пользователем фиксированного множества именованных констант. Называется перечислением, так как поддерживает автоматическое сопоставление имен уникальным числовым константам, ранжированным в порядке увеличения - то есть, перечисляет константы * **Ассоциативный массив**, **словарь** или **хэш-таблица** - структура данных, сопоставляющая значения одного типа значениям другого типа. * **Множество** - неупорядоченный набор однотипных значений, каждый элемент которого уникален. ===== Сильная и слабая типизация ===== Примитивные типы имеют ограниченный диапазон возможных значений. Например, тип char обычно имеет длину 8 бит и, соответственно, имеет 256 возможных значений. Если попытаться преобразовать (привести) 32-битный целочисленный тип к типу char, произойдет потеря точности: верхние байты будут срезаны. Это считается небезопасным, так как может привести к трудноуловимым багам при бездумном использовании. Типизация языка называется сильной, если в нем приведение типов с потерей точности отсутствует в принципе, либо всегда осуществляется явно. В противоположность этому, языки со слабой типизацией допускают неявное приведение типов с потерей точности - например, при сохранении значения в переменную. Некоторые компиляторы при этом могут выводить предупреждение. Примеры языков со слабой типизацией: C, C++. Примеры языков с сильной типизацией: Java, C#, D, Rust, Pascal, Lisp, ML, Haskell. ===== Вывод типов и вычисление во время компиляции ===== В языке с сильной статической типизацией тип любого выражения может быть определен (выведен) семантическим анализатором на основе заданных правил совместимости типов. В некоторых языках это позволяет, например, опустить тип при объявлении переменной, если она инициализируется литералом или выражением. Вывод типов поддерживается в ML, Haskell, F#, D, C++11, Go, Rust, Dart, Scala, Vala, Swift. Некоторые языки расширяют эту идею возможностью вычисления выражения во время компиляции (compile-time evaluation, CTE), если все входные данные выражения известны заранее. Эта возможность даже может включать выполнение функций, не имеющих побочных эффектов (compile-time function execution, CTFE). На момент написания статьи CTFE поддерживается в Lisp, D и C++14.