19.2. Обзор 199
именем, что и у поля; вначеле зовется конструктор super для инициализации полей надкласса; затем
оставшиеся поля инициализируются значениями соответствующих параметров. В нашем примере над-
классом всех приведенных классов служит Object, где никаких полей нет, так что вызовы super не
имеют аргументов. Конструкторы — единственное место, где в программах на FJ встречаются super
и =. Поскольку в FJ нет оепраций с побочными эффектами, тело метода всегда состоит из оператора
return с параметром-телом, как можно видеть на примере setfst.
В FJ есть пять видеов термов. В нашем примере new A(), new B() и new Pair(...) — конструкторы
объектов, а ....setfst(...) — вызов метода. В теле setfst, терм this.snd является обращением к
полю, а вхождения newfst и this — переменные.
1
В контексте приведенных опеределений, терм
new Pair ( new A() , new B ()). setfs t ( new B ())
дает при вычислении new pair(new B(), new B()).
Оставшийся пятый вид термов – приведение типа (см. 15.5.1). Терм
(( Pair ) new Pair ( new Pair ( new A () , new B ()) ,
new A ()). fst ). snd
дает при вычислении new B(). Подтерм (Pair)t, где t равняется new Pair(...).fst, является приведе-
нием типа. Это приведение необходимо, поскольку t — обращение к полю fst, про который объявлено,
что он содержит объект типа Object, в то время как следующее обращение к полю snd определено
только для объектов типа Pair. Во время выполнения правила вычисления проверят, принадлежит ли
объект класса Object, хранимый в поле fst, классу Pair (в данном случае проверка будет успешной).
Отказ от побочных эффектов приводит к приятному побочному эффекту: вычисление можно цели-
ком формализовать в рамках синтаксиса FJ, не обращаясь к дополнительным механизмам для модели-
рования кучи (см. Главу 13). Имеется три основных правила вычисления: одно для обращения к полю,
одно для вызова метода и одно для приведения типа. Напомним, что в лямбда-исчислении правило
вычисления для применений предполагает, что функция сведена к лямбда-абстракции. Подобным об-
разом, в FJ правила вычисления предполагают, что объект, над которым ведется работа, сведен к терму
new. В лямбда-исчислении действует лозунг «все на свете функции», здесь «все на свете объекты».
Следующий пример показывает правило для обращения к полям (E-ProjNew) в действии:
new Pair(new A(), new B()).snd new B()
Посколльку действует стилизованный синтаксис конструкторов объектов, мы знаем, что конструктор
содержит по одному параметру для каждого поля, в том же порядке, в котором эти поля объявлены.
Здесь это поля fst и snd, и обращение к полю snd выбирает второй параметр.
Вот как действует правило для вызовов метода (E-InvkNew):
new Pair (new A(), new B()).setfst(new B())
newfst new B()
this new Pair(new A(),new B())
new Pair(newfst, this.snd)
т. е., new Pair(new B(), new Pair(new A(), new B()).snd)
Получаетелем при вызове метода является объект new Pair(new A(),new B()), так что мы ищем ме-
тод setfst в классе Pair, и видим, что этот метод имеет формальный параметр newfst и тело new
Pair(newfst, this.snd). Вызов метода сводится к телу, в котором формальный параметр заменяется
на актуальный, а особая переменная this заменяется на объект-получатель. Это подобно правилу бета-
редукции (E-AppAbs) в лямбда-исчислении. Основные отличия том, что класс получателя определяет,
где следует искать тело метода (при этом поддерживается переопределение методов в подклассах), и
замена переменной this на получатель (при этом поддерживается «открытая рекурсия через self»).
2
Подобно лямбда-исчислению, в FJ, ситуация, когда параметр встречается в теле более одного раза,
1
В отличие от Java, в синтаксисе FJ this считается переменной, а не ключевым словом
2
Читатели, знакомые с исчислением объектов Абади и Карделли (Abadi and Cardelli 1996), увидят много общего и их
правилом ς-редукции.
rev. 104