В шаге от varargs
Jan. 27th, 2022 06:14 pmНеизвестно, почему именно, но оба Паскаля на БЭСМ-6 обладают уникальным (по сравнению со стандартным Паскалем и с P-code UCSD Паскалем) свойством: в них можно передавать подпрограммы в качестве параметров подпрограмм (в отличие от UCSD Паскаля), но полный прототип формального параметра не указывается (в отличие от стандартного Паскаля).
По стандарту надо, например, так:
И при попытке вызвать foo с аргументом-функцией, описанной не как принимающую целый аргумент и возвращающую целое, будет ошибка компиляции.
В БЭСМ-овских Паскалях не так. В них надо
Вызывать foo можно с аргументом-функцией, возвращающей целое, принимающей любое число аргументов, и это скомпилируется, а ошибка, если переданная функция принимает не один аргумент, или принимает что-либо, несовместимое с целым числом, то будет зафиксирована ошибка времени выполнения.
Сделано это следующим образом: когда вызывается подпрограмма, переданная как формальный параметр, то генерируется табличка, описывающая типы её параметров, и передается вызываемому формальному параметру.
Когда же какая-либо подпрограмма передается как фактический параметр, то для неё генерируется вставка, которая проверяет соответствие таблички реальному набору параметров подпрограммы, и передает управление или на собственно подпрограмму или на сообщение об ошибке, и в вызываемую процедуру передается адрес этой вставки. Таким образом можно было, например, написать,
чего нельзя было ни в одном другом известном Паскале.
Понятно, что отсюда рукой подать до реализации type-safe varargs, если добавить флаг, требующий формирования таблички при каждом вызове (с переиспользованием, если точно такая же уже была), и API для работы с табличкой и получения очередного аргумента явным образом. Но увы, не сложилось.
По стандарту надо, например, так:
function foo(function bar(i:integer):integer):integer;
begin
foo := bar(5) + bar(10)
end;И при попытке вызвать foo с аргументом-функцией, описанной не как принимающую целый аргумент и возвращающую целое, будет ошибка компиляции.
В БЭСМ-овских Паскалях не так. В них надо
function foo(function bar:integer):integer;
begin
foo := bar(5) + bar(10)
end;Вызывать foo можно с аргументом-функцией, возвращающей целое, принимающей любое число аргументов, и это скомпилируется, а ошибка, если переданная функция принимает не один аргумент, или принимает что-либо, несовместимое с целым числом, то будет зафиксирована ошибка времени выполнения.
Сделано это следующим образом: когда вызывается подпрограмма, переданная как формальный параметр, то генерируется табличка, описывающая типы её параметров, и передается вызываемому формальному параметру.
Когда же какая-либо подпрограмма передается как фактический параметр, то для неё генерируется вставка, которая проверяет соответствие таблички реальному набору параметров подпрограммы, и передает управление или на собственно подпрограмму или на сообщение об ошибке, и в вызываемую процедуру передается адрес этой вставки. Таким образом можно было, например, написать,
function foo(n:integer; function bar:real; a, b, c:real):real; begin case n of 0: foo := bar; 1: foo := bar(a); 2: foo := bar(a, b); 3: foo := bar(a, b, c) end end;
чего нельзя было ни в одном другом известном Паскале.
Понятно, что отсюда рукой подать до реализации type-safe varargs, если добавить флаг, требующий формирования таблички при каждом вызове (с переиспользованием, если точно такая же уже была), и API для работы с табличкой и получения очередного аргумента явным образом. Но увы, не сложилось.
no subject
Date: 2022-02-01 09:17 pm (UTC)no subject
Date: 2022-02-02 05:42 am (UTC)