Выбрать главу

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

Объявления констант должны быть вне тела любых подпрограмм. Константы могут быть глобальными или местными (локальными), но не частными.

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

Объявления местных имён на уровне файла, вне тела любых подпрограмм, не должны находиться внутри тела команд циклов (for, while) или тела команды ветвления (if).

Управляющая переменная, используемая в команде цикла for, является особым случаем. Она автоматически объявляется перед началом циклических расчётов, и её сцена ограничена телом команды циклa. Если команда цикла расположена внутри тела подпрограммы, переменная цикла является частной переменной и должна иметь имя, отличающееся от всех других объявленных частных переменных данной подпрограммы (к которым относятся и переменные, объявляемые в списке аргументов). Когда команда цикла находится на уровне файла, вне тела любых подпрограмм, переменная цикла является местной (локальной) переменной и должна иметь имя, отличающееся от всех других уже объявленных местных переменных данного файла. Но вы можете использовать одно и то же имя переменной цикла для различных циклов, если циклы не являются вложенными один в другой. Вам не нужно объявлять тип переменной цикла так, как это делается с другими переменными. Диапазон значений переменной цикла, задаваемый в команде цикла, определяет и все её законные значения, следовательно, любое добавочное задание её типа было бы излишним и поэтому не предусмотрено.

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, который означает допустимость любого значения. Подпрограммы могут быть написаны для работы с очень специфическими или с очень общими типами данных.