Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Хорошие идеи взгляд из Зазеркалья.doc
Скачиваний:
7
Добавлен:
04.11.2018
Размер:
151.55 Кб
Скачать
          1. Лазейки (loopholes)

Я рассматриваю лазейки как одно из наихудших средств, хотя сам заразил этим убийственным вирусом Pascal, Modula и даже Oberon. Лазейка позволяет программисту взломать проверку типов компилятора и сказать: "Не вмешивайтесь. Я умнее правил". У лазеек имеется много форм. Наиболее распространены функции явного изменения типа, такие как

Mesa: x := LOOPHOLE[i, REAL]

Modula: x := REAL(i)

Oberon: x := SYSTEM.VAL (REAL, i)

Но они могут маскироваться под спецификации абсолютных адресов или под записи с вариантами, как в языке Pascal. В предшествующих примерах внутреннее представление целого значения i должно интерпретироваться как число с плавающей точкой x. Это можно делать только при наличии знания о представлении чисел, что не должно требоваться при работе на уровне абстракции, обеспечиваемом языком.

В Pascal и Modula [3] лазейки, по крайней мере, демонстрируются открытым образом. В языке Oberon они представлены только через небольшое число функций, инкапсулированных в псевдокод, называемый SYSTEM, который должен импортироваться и, таким образом, становиться видимым в заголовке любого модуля, в котором используются такие низкоуровневые возможности.

Это может звучать как попытка оправдания, но, тем не менее, лазейки являются плохой идеей. Они были введены для обеспечения возможности реализации законченных систем с использованием единственного языка программирования. Например, у менеджера памяти должна иметься возможность представления памяти как плоского массива байт без типов данных. У него должна иметься возможность выделять и освобождать блоки независимо от ограничений типов. Другим примером потребности в лазейках является драйвер устройства. В ранних компьютерах имелись специальные инструкции для доступа к устройствам. Позже программисты присвоили устройствам специальные адреса памяти, отобразили их в память. Поэтому появилась идея разрешить задавать для некоторых переменных абсолютные адреса, как в языке Modula. Но этой возможностью можно злоупотреблять многими нелегальными способами.

Очевидно, что нормальный пользователь никогда не нуждается в программировании менеджера памяти или драйвера устройства, и, следовательно, ему не нужны эти лазейки. Однако - и именно это делает лазейки плохой идеей - лазейки по-прежнему находятся в распоряжении программистов. Опыт показал, что нормальные пользователи не будут избегать использования лазеек, а скорее с энтузиазмом ухватятся за них, как за замечательное средство, которое будет ими использоваться при всякой возможности. Это особенно проявляется, если в руководстве программирования содержатся предостережения по поводу использования лазеек.

Наличие возможности лазеек обычно указывает на недостаточное совершенство языка, показывая, что на языке невозможно выразить некоторые вещи, которые могут оказаться важными. Например, тип ADDRESS в Modula приходилось использовать для программирования структур данных с элементами разных типов. Строгая стратегия статической типизации, которая требовала, чтобы каждый указатель был статически ассоциирован с фиксированным типом и мог ссылаться только на такие объекты, делала это невозможным. Зная, что указатели являются адресами, лазейка в форме невинно выглядящей функции изменения типа обеспечивала эту возможность, позволяя указательным переменным указывать на объект любого типа. Недостаток состоял в том, что никакой компилятор не мог проверить корректность таких присваиваний. Система проверки типов блокировалась и с таким же успехом могла бы вовсе отсутствовать. В языке Oberon [4] было применено чистое решение проблемы расширения типа, называемое в объектно-ориентированных языках наследованием. Теперь стало возможным объявить указатель как ссылающийся на данный тип, и этот указатель мог указывать на любой тип, являющийся расширением данного типа. Это позволяло конструировать неоднородные структуры данных и безопасно использовать их при поддержке надежной системы проверки типов. Реализация требовала проверки во время выполнения только в тех случаях, когда было невозможно произвести проверку во время компиляции.

Программы, представленные на языках 1960-х, были полны лазейками, что делало их весьма подверженными ошибкам. Но тогда отсутствовала какая-либо альтернатива. Тот факт, что разработчики могут использовать язык, подобный Oberon, для программирования без использования лазеек систем целиком, за исключением менеджера памяти и драйверов устройств, характеризует наиболее существенный прогресс в разработке языков за последние 40 лет.