Лекция №23Интерфейсы и типы данных: системы типов данных
Основное применение систем типов данных в языках программирования — минимизация появления ошибок, связанных с неправильной интерпретацией данных. В «идеальном» языке с точки зрения типобезопасности результат любой операции — корректное значение типа данных, который может быть определен заранее (например, во время компиляции).
На практике каждый язык программирования устанавливает свои рамки безопасности типов:
- Языки со слабой типизацией, такие как C и C++, позволяют интерпретировать данные предельно широко. С одной стороны, это может повысить эффективность работы приложения, с другой — приводит к трудно находимым дефектам.
- Языки с сильной типизацией накладывают ограничения на потенциально опасные операции, например, неявные преобразования типов. Например, в Python, в отличие от большинства языков программирования, не выполняется автоматического приведения чисел к строкам.
К сожалению, обеспечение абсолютного отсутствия ошибок типов — чрезвычайно трудоемкая задача (фактически, частный случай верификации исходного кода программы), поэтому в современных языках программирования роль системы типов состоит в устранении наиболее тривиальных ошибок; их дальнейший поиск — задача, решаемая в процессе тестирования. В этом плане видна тенденция к увеличению роли человеческого фактора: большинство современных языков программирования (Python, Ruby, JavaScript) обладают динамической типизацией, то есть проверка ошибок типов происходит во время выполнения программы.
Каждая система типов по-своему определяет совместимость типов, то есть соответствие фактического типа данных ожидаемому:
- В случае структурной типизации (большинство функциональных ЯП) типы совместимы, если они обладают одинаковой внутренней структурой. Требуемая структура входящих данных определяется для каждого элемента программы во время компиляции.
- Утиная типизация похожа на структурную, однако проверка типов происходит во время выполнения программы по отдельности для каждого утверждения. Языки с утиной типизацией, такие как Python, позволяют повысить адаптируемость программы.
- При номинальной типизации (например, в Java, C#, C++) совместимость типов определяется в исходном коде программы на основе явных деклараций.
Важный аспект совместимости типов в объектно-ориентированном программировании — это отношение «тип — подтип», означающий наследование интерфейса объектов. Согласно принципу подстановки Барбары Лисков, любой подтип может использоваться в произвольном контексте, если там может использоваться родительский тип данных. Определение подтипов и наследование (то есть копирование реализации) — различные по своему смыслу операции, взаимоотношение между которыми зависит от языка программирования:
- Наследование с модификаторами protected и private в C++ нарушает интерфейс класса (публичные методы теряют видимость).
- В Java и C# интерфейсы можно расширять; разумеется, о наследовании тут речи не идет по причине отсутствия реализации.