Читаем Основы объектно-ориентированного программирования полностью

[x]. С точки зрения практики, некоторые оптимизации компилятора становятся невозможными, если требуется, чтобы компилятор вычислял операнды в заданном выражением порядке, как в случае с некоммутативными операторами. Поэтому лучше использовать стандартные операторы, если известно, что оба операнда определены.

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

b := ((i /= 0) and then (j // i = k))

можно написать

if i = 0 then b := false else b := (j // i = k) end

Нестрогая форма, конечно, проще. Это особенно ясно, когда она используется как условие выхода из цикла:

from

i := a.lower

invariant

-- Для всех элементов из интервала [a.lower .. i - 1], (a @ i) /= x

variant

a.upper - i

until

i > a.upper or else (a @ i = x)

loop

i := i + 1

end;

Result := (i <= a.upper)

Цель - сделать Result верным, если и только если значение x находится в массиве a. Использование or здесь будет неверным. В этом случае всегда могут вычисляться два операнда, так что при истинности первого операнда (i > a.upper) произойдет попытка доступа к несуществующему элементу массива a @(aupper+1), что приведет к ошибке во время выполнения (нарушение предусловия при включенной проверке утверждений).

Решение без нестрогих операторов будет неэлегантным.

Другой пример - утверждение, например, инварианта класса, выражающее, что первое значение списка l целых неотрицательно, при условии, что список непустой:

l.empty or else l.first >= 0

При использовании or инвариант был бы некорректен. Здесь нет способа написать условие без нестрогих операторов (кроме написания специальной функции и вызова ее в утверждении). Базовые библиотеки алгоритмов и структур данных содержат много таких случаев.

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

(not l.empty) implies (l.first >= 0)

<p>Строки</p>

Класс STRING описывает символьные строки. Он имеет специальный статус, поскольку нотация допускает манифестные строковые константы, обозначающие экземпляры STRING.

Строковая константа записывается в двойных кавычках, например,

"ABcd Ef ~*_ 01"

Символ двойных кавычек должны предваряться знаком %, если он появляется как один из символов строки.

Неконстантные строки также являются экземплярами класса STRING, чья процедура создания make принимает в качестве аргумента ожидаемую начальную длину строки, так что

text1, text2: STRING; n: INTEGER;

...

create text1.make (n)

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

На экземплярах STRING доступны многочисленные операции: сцепление, выделение символов и подстрок, сравнение и т.д. (Они могут изменять размер строки, автоматически запуская повторное размещение, если размер строки становится больше текущего.)

Присваивание строк означает разделение (sharing): после text2 := text1, любая модификация text1 модифицирует text2, и наоборот. Для получения копии строки, а не копии ссылки, используется клонирование text2 := clone (text1).

Константную строку можно объявить как атрибут:

message: STRING is "Your message here"

<p>Ввод и вывод</p>

Два класса библиотеки KERNEL обеспечивают основные средства ввода и вывода: FILE и STD_FILES.

Среди операций, определенных для объекта f типа FILE, есть следующие:

create f.make ("name") -- Связывает f с файлом по имени name.

f.open_write -- Открытие f для записи

f.open_read -- Открытие f для чтения

f.put_string ("A_STRING") -- Запись данной строки в файл f

Операции ввода-вывода стандартных файлов ввода, вывода и ошибок, можно наследовать из класса STD_FILES, определяющего компоненты input, output и error. В качестве альтернативы можно использовать предопределенное значение io, как в io.put_string ("ABC"), обходя наследование.

<p>Лексические соглашения</p>

Идентификатор - это последовательность из символа подчеркивания, буквенных и цифровых символов, начинающаяся с буквы. Нет ограничений на длину идентификатора, что позволяет сделать ясными имена компонентов и классов.

Перейти на страницу:

Похожие книги