Книга: Язык программирования Euphoria. Справочное руководство

2.4.3 Задание типа переменной

2.4.3 Задание типа переменной

Мы уже видели несколько примеров, касающихся типов переменных, но теперь мы дадим типам более развёрнутое и точное определение.

Объявления переменных как таковые записываются в виде имени типа, сопровождаемого списком имён переменных данного типа, которые мы решили объявить как подлежащие дальнейшему использованию в программе. Например,

object a
global integer x, y, z
procedure fred(sequence q, sequence r)

Типы: object (объект), sequence (ряд), atom (число, атом) и integer (целое) являются предопределёнными. Переменная типа object может принимать любое значение. Те переменные, который объявлены с типом sequence, должны всегда быть рядами. Те переменные, которые объявлены с типом atom, должны всегда быть атомами. А те, которые объявлены с типом integer, должны быть атомами с целочисленной величиной в диапазоне от -1073741824 до +1073741823 включительно. Вы можете выполнять точные целочисленные расчёты с величинами, и выходящими из диапазона integer, вплоть до примерно 15 десятичных знаков, но тогда должны объявлять под них переменные типа atom, а не integer.

Примечание: В списке аргументов процедуры или функции, как это показано, к примеру, для процедуры fred(), имя типа должно сопровождаться единственным именем переменной-аргумента. Примечание о производительности: Вычисления с использованием переменных, объявленных как integer, будут обычно более быстрыми, чем вычисления с переменными, объявленными как atom. Если ваша машина имеет сопроцессор плавающей точки, Euphoria будет использовать его для работы с атомами, которые непредставимы как integer. Если на вашей машине сопроцессор отсутствует, Euphoria будет вызывать подпрограммы арифметики плавающей точки, которые имеются в интерпретаторе ex.exe (или у Windows). Вы можете заставить ex.exe обходить сопроцессор, установив переменную окружения:

SET NO87=1

При этом будут использованы сравнительно медленные встроенные подпрограммы, но здесь может быть и некоторое преимущество, если вы, к примеру, обеспокоены наличием ошибки сопроцессора в некоторых ранних версиях микросхем Pentium. Если предопределённые типы не вполне соответствуют вашей задаче, вы можете создать свои собственные типы. Всё, что нужно сделать для этого - написать функцию с единственным аргументом, но объявить её как type ... end type вместо function ... end function. Например,

type hour(integer x)
return x = 0 and x <= 23
end type
hour h1, h2
h1 = 10 -- ok
h2 = 25 -- ОШИБКА! Программа прерывается с сообщением

Переменным h1 и h2, объявленным с типом hour (час), может быть присвоена только целочисленная величина в диапазоне от 0 до 23 включительно. После каждого присваивания h1 или h2 интерпретатор будет вызывать тип hour(), подавая новую величину. Величина сначала будет проверена на соответствие типу integer (объявлена как "integer x"). Если соответствует, то будет вычисляться выражение, подаваемое в команду return, чтобы проверить значение x (т.е. новую величину h1 или h2). Если hour() выдаёт значение "истина", исполнение программы продолжается. Если hour() выдаёт значение "ложь", программа прерывается с соответствующим диагностическим сообщением.

Тип "hour" может использоваться также для объявления аргументов подпрограммы:

procedure set_time(hour h)

Процедура set_time() может быть вызвана только с подходящей величиной аргумента h, иначе программа будет прервана с сообщением.

Тип переменной будет проверяться после каждого присваивания переменной нового значения (за исключением тех случаев, когда компилятор может предварительно определить, что в проверке нет необходимости, и программа будет немедленно прерываться, если функция типа выдаёт ложь. Типы аргументов подпрограммы проверяются при каждом вызове подпрограммы. Эта проверка гарантирует, что переменная никогда не может иметь величину, не принадлежащую к типу данной переменной.

В отличие от других языков, тип переменной не затрагивает никакие вычисления, производимые над переменной. В выражении играет роль только величина переменной. Тип служит только для проверки отсутствия ошибки, чтобы предотвратить любую "порчу" переменной.

Типы, которые вы определяете в своей программе, могут отлавливать в вашей программе неожиданные логические ошибки. Но они не предназначены для перехвата или корректуры ошибок в данных, вводимых пользователем программы.

Проверка типов может быть выключена или включена между подпрограммами с помощью специальных команд with type_check (с проверкой типа) или without type_check (без проверки типа). По умолчанию проверка типов включена при старте программы.

Примечания о проверках производительности: Сравнивая скорость программы Euphoria со скоростью программ, написанных на других языках, в начале программы Euphoria необходимо написать without type_check. Эта команда даёт интерпретатору Euphoria разрешение пропускать проверки типов во время исполнения программы, чтобы сэкономить некоторое время. Все остальные проверки будут при этом выполняться, т.е. по индексам, инициализации и т.п. Даже при выключенной вами проверке типов интерпретатор Euphoria оставляет за собой право делать эту проверку в стратегически важных местах, так как она на деле позволяет вашей программе исполняться быстрее во многих случаях. Следовательно, вы можете получить отказ по проверке типа, даже когда проверку выключаете. Включена проверка типов или выключена, вы никогда не получите исключительную ситуацию машинного уровня. У вас всегда будет внятное сообщение от Euphoria, если что-то пошло неправильным путём. (Конечно, и здесь можно нарваться на машинное исключение, например, когда вы делаете poke (размещаете данные непосредственно в памяти), или вызываете подпрограммы, написанные на C или в машинном коде. Но это уже совсем другая история - в этих случаях Euphoria просто уважает ваше неотъемлемое право давать вашей машине любые ваши команды.) Метод определения типов в Euphoria проще, чем те, которые вы найдёте в других языках, хотя Euphoria обеспечивает программиста значительно большей гибкостью в описании законных величин для типов данных. Вы можете использовать любой алгоритм для включения величин в допустимый диапазон или их исключения из него. Вы можете даже позволить переменной быть типа object, который означает допустимость любого значения. Подпрограммы могут быть написаны для работы с очень специфическими или с очень общими типами данных.

Но во многих программах забота о каких-то новых типах данных не приносит значительных преимуществ, и вам может вполне хватить четырёх имеющихся предопределённых типов. В отличие от других языков, механизм типов Euphoria даёт вам более свободный выбор. А с типом object вы можете и не вспоминать о наличии остальных трёх.

Тем не менее, для крупных программных проектов определение более конкретных типов может помочь в процессе отладки. Со строго конкретными типами данных логические ошибки отлавливаются вблизи места их зарождения и их распространение по скрытным путям в другие части программы пресекается. Более того, всегда проще размышлять о причинах неправильного поведения некоторого небольшого участка кода, когда у вас есть гарантия, что используемые здесь переменные всегда имели законную величину, а вот требуемый результат отсутствует.

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

Анекдот 1: Перенеся большую программу C на Euphoria, мы обнаружили ряд скрывавшихся ранее ошибок. Хотя данная программа C и заслужила большое доверие как якобы тотально "корректная", мы нашли: ситуацию, где считывалась неинициализированная переменная; место, где элемент номер "-1" одного из массивов беспрепятственно записывался и считывался; ситуацию, где что-то выводилось как раз мимо экрана. Эти проблемы вели к ошибкам, которые были не слишком заметны для не очень внимательного наблюдателя, и код C успешно прошёл тестирование. Анекдот 2: Алгоритм Quick Sort, представленный на странице 117 "Написания эффективных программ" Джона Бентли, имеет ошибку индексирования! Этот алгоритм будет иногда считывать элемент из памяти непосредственно перед началом сортируемого массива, и будет считывать из памяти элемент непосредственно после конца массива. Хотя и читается какой-то мусор, оставшийся от другой программы, алгоритм всё ещё работает - вероятно, поэтому ошибка никогда и не была обнаружена. Но что, если бы по тем адресам вне массива не было никакой (виртуальной) памяти? Бентли позже модифицировал алгоритм так, что эта ошибка уходит -- но он представлял и раннюю версию как правильную. Даже экспертам нужна проверка правильности индексирования!Примечания о производительности: Когда программист широко применяет свои собственные типы, их проверка интерпретатором добавляет ко времени исполнения программы всего 20..40 процентов. Оставляйте проверку включенной, если вам не нужна действительная экстра-скорость. Вы можете также предусмотреть её выключение только для нескольких особенно сильно загруженных вычислениями подпрограмм. Профилирование может помочь в принятии правильного решения.

Оглавление книги


Генерация: 1.740. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз