:h1.Первая страница
:p.
R-5 - язык программирования, созданный в 2005-2015 годы для того, чтобы написать 
препроцессор для языка C и в дальнейшем составлять программы на нём в соответствии 
с положениями и рекомендациями стандарта MISRA-C<:>2004, а также программировать на 
защищённых диалектах языка C, таких, как Cyclone. Это позволило бы ускорить решение
некоторых задач, где требовался именно C и не подходил ни один язык высокого уровня.

:p.
Новый язык был назван в честь фигурки из игры "The Game of Life", а за основу для 
него был выбран Classic Rexx.

:p.
Сегодня Rexx уже забыт - но именно он использует приёмы программирования, 
которые оказались наиболее подходящими для решения выбранной задачи. Rexx 
применяет сочетание процедурного и функционального подходов, когда, с одной 
стороны, алгоритмы записываются в виде последовательности команд, где разделены 
существительные и глаголы (и это особенность процедурных языков), но, с другой 
стороны, состояние программы хранится в области временных переменных и передаётся 
от одной функции к другой (и это уже особенность функциональных языков). Программы 
на R-5 изначально должны были работать с исходными текстами на других языках, и 
уже во во время проектирования нового языка стало ясно, что для него требуется 
именно этот подход к написанию программ.

:p.
R-5 не использует глобальные переменные, а состояние программы (то есть все данные) 
передаётся в виде структуры данных от одной функции к другой. Программы, как обычно, 
работают с изменяемым состоянием, но первым действием с переменной должна быть запись 
значения, при этом тип переменной менять нельзя. В следующем примере записана функция, 
выполняющая цикл, и первое действие в ней - объявление переменных. Они могут быть 
объявлены и не только в начале функции, но их создание - обязательное действие, и 
его нельзя обойти.

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Average.rc'.
:font facename=default.

:p.
Для сравнения, в языке Lisp переменная может стать глобальной в том случае, если 
её название начинается и заканчивается символом "*", а без этих символов переменная 
останется локальной. В языках Lua и JavaScript все переменные по умолчанию глобальные 
(то есть, они изначально считаются глобальными, если не указано обратное), в языках 
Python и PHP глобальными становятся переменные, созданные вне функций, а в языках 
Pascal и С глобальные переменные объявляются в заголовке программы. Роль глобальных 
переменных исполняют поля в объектах во всех без исключения ООП-языках, таких, как 
C#, C++ и Java. И всё это "драгоценное наследие" было выброшено за борт, вместе со 
всем программным кодом на них.

:p.
Кроме запрета на глобальные переменные, R-5 имеет и другие особенности. Все функции 
и все условия и циклы записываются в одной и той же последовательности: вначале стоят 
вычисления, а затем операторы условия и возврата. Пример одной из них показан выше -
это вычисление среднего значения в массиве или списке чисел или структур данных, где 
вначале объявляются переменные и запускается цикл, а затем выполняется оператор условия 
и каждая из его веток возвращает значение.

:p.
Написанные программы компилируются в синтаксическое дерево, которое может быть выполнено 
в другой программе (в том числе Web-сервером или электронной таблицей), либо транслировано 
в байт-код или код на языке C, который затем переводится в машинный код. Это позволило бы 
сделать версию языка, не зависящую от операционной системы и оборудования - но транслятор
с R-5 сейчас написан под OS/2, и в ближайшем будущем других версий не будет.

:p.
Данная книга - не учебник. Её цель - создать по возможности полный стандарт языка
R-5, и она с самого начала была задумана как описание языка и связанных с ним 
библиотек, а не как пособие для начинающих, позволяющее, как об этом иногда пишут 
на форумах, "быстро начать программировать" на нём. Быстро изучить именно этот язык 
не получится - более того, он устроен таким образом, чтобы не допускать подобного.

:p.
В отличие от справочных пособий, рассказывающих об основных приёмах программирования 
начиная с операторов перехода, условия и цикла (именно так и написаны большинство книг 
для школьников и студентов), здесь "основой основ" считаются функции - части программ, 
принимающие и выдающие данные. В первых главах книги рассматривается вопросы о том, как 
передавать им параметры, и в том числе как передать функцию на вход другой функции, как 
вернуть функцию из другой функции и так далее. Затем на их основе создаются операторы 
условий и циклов (и то и другое - функции), затем в книге появляются рекурсивные вызовы 
и хвостовая рекурсия, преобразователи данных и функции-переходники, а также макросы и 
операторы для записи действий с данными в алгебраической форме. В конце книги стоят 
главы о работе с базами данных и передаче данных по сети, а также краткое описание 
стандартной библиотеки.

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

:p.
Но я заранее должен предупредить, что тем, кто пишет складской учёт или Web-сайты на 
языках с низким порогом вхождения ("после нас - хоть потоп") мне предложить нечего.

.*

:h2.Цвета и шрифты
:p.
Для выполнения программ на R-5 требуется операционная система, где была бы страничная 
память, многопоточное выполнение, оконная оболочка и доступ к сети. Для составления 
этих программ требуется текстовый редактор, способный подсвечивать ключевые слова, а 
также шрифты с постоянной шириной символов, которые выглядели бы примерно так, как на 
следующем рисунке:
.br
:artwork align='center' name='0001-Intro\Images\MrEd.bmp'.
.br
Правильный выбор шрифта очень важен для языков программирования, использующих текстовый 
синтаксис, где основные ключевые слова - глаголы и частицы, с которых обычно начинаются
предложения в разговорной речи. Расстояние между строками должно быть достаточно большим, 
а буквы должны быть достаточно широкими: всё это улучшает читаемость программ. Заглавные 
и строчные буквы и пробелы - отдельный вопрос, который рассматривается в следующей главе.

:p.
Ещё одно правило действует в отношении синего цвета: он может быть использован только 
с добавлением голубого или зелёного (а лучше - и того и другого вместе). Средний цвет 
не должен быть синим: это либо тёмно-бирюзовый, либо дымчатый синий, либо цвет морской 
волны - и например, файловые менеджеры показывают текст голубым по синему, а белым или
жёлтым. Яркий синий слишком бросается в глаза и в текстовых редакторах не используется.

.*

:h2.Названия, отступы и пробелы
:p.
Помимо привязки к определённым шрифтам, R-5 требует исполнения большого количества
правил и соглашений - и в том числе соглашений о том, как называть переменные и 
функции, как задавать ключевые слова, где добавлять пустые строки, как расставлять 
отступы и ставить пробелы и так далее. Например, следующая строка считается верной:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Spaces-1.rc'.
:font facename=default.

:p.
И здесь:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Spaces-2.rc'.
:font facename=default.

:p.
А следующая строка считается ошибочной:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Spaces-3.rc'.
:font facename=default.

:p.
И здесь:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Spaces-4.rc'.
:font facename=default.

:p.
Просто потому, что в строке неправильно поставлены пробелы. "Стиль кодирования", 
таким образом, задаётся на уровне самого языка - и должен поддерживаться всеми, 
кто пишет на нём. Как нетрудно догадаться, желающих найдётся немного. Зато они 
будут понимать код друг друга, и поддержка и обновление уже написанных программ 
станет простой задачей.

.*

:h2.Типы данных и операции с ними
:p.
Каждой переменной в программе даётся название ("имя переменной") и с ней обязательно
связывается тип данных - набор правил, согласно которым для каждой переменной задаются 
действия, которые могут быть с ней выполнены. Для чисел это сложение, умножение, вычитание, 
деление и другие действия, для строк это поиск и замена строки в строке, для массивов и 
списков это добавление элемента, перебор элементов в цикле, отсоединение первого элемента 
и так далее. В отношении некоторых типов R-5 ведёт себя особенно строго, не позволяя, 
например, работать со строками как с числами - эта особенность языка будет рассмотрена 
отдельно.

:p.
Типы данных проще всего показать на примерах. В следующем примере при подсчёте средней
величины функция "Average()" складывает элементы массива и делит сумму на их количество:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-1.rc'.
:font facename=default.

:p.
А в следующем примере для выполнения этого действия пришлось добавить к ней дополнительную
преобразующую функцию, которая из каждого элемента массива создаёт число:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-2.rc'.
:font facename=default.

:p.
Без этой функции, заданной в скобках, пример работать не будет: для строк не определены 
арифметические операции, и работать с ними как с числами нельзя - даже если они содержат 
цифры:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-3.rc'.
:font facename=default.

:p.
Зато для строк были придуманы операторы-стрелки, ставшие отличительной чертой языка:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-4.rc'.
:font facename=default.

:p.
Кроме того, удалось создать короткую запись для действий с датой и временем:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-5.rc'.
:font facename=default.

:p.
А также сократить матричные вычисления:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-6.rc'.
:font facename=default.

:p.
Здесь умножение, транспонирование и поиск обратной матрицы выглядят как арифметические 
действия и вызовы функций, но на самом деле это операторы языка, написанные для типов 
данных "Vector" и "Matrix", которые выполнены как одномерные и двумерные массивы. Тем 
не менее, как только они были названы "матрицами" и "векторами", для них появились 
дополнительные действия, которые не определены для обыкновенных массивов.

:p.
Наличие типов данных также позволило добавить в язык элементы объектно-ориентированного
программирования, и хотя R-5 по-прежнему остаётся процедурным языком, переменные и 
код для работы с ними связываются в программах так же, как это делается в ООП. Так что 
в программе можно, например, выбирать элементы из массива или списка и вызывать для них 
функцию расчёта площади - вот так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-7.rc'.
:font facename=default.

:p.
При этом настоящий тип данных переменной "Letter" может меняться - но код будет верным,
если для каждого типа данных определены функции с заданными именами. Одна из функций в
примере выше может быть задана для всех типов данных (в этом случае считается, что она 
была ими унаследована от родительского типа), другая - была написана для каждого типа
(и в этом случае её называют "виртуальной" функцией), но язык программирования устроен
таким образом, что на данном уровне это уже не заметно.

:p.
И наконец, ещё одна возможность, которую дают описания типов - возможность размещения
массивов структур данных в сплошных областях памяти с выравниванием адресов по границам 
2^N. Такие данные можно передать функциям, написанным на чистом C, "как в старые добрые 
времена", получив увеличение быстродействия за счёт более плотного размещения данных в 
памяти - так, чтобы они заранее считывались в кеш процессора:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\DataTypes-8.rc'.
:font facename=default.

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

:p.
Как видно из примеров выше, в большинстве случаев указывать тип данных при создании 
переменной необязательно. Компилятор умеет выводить типы, и задавать их надо только 
в некоторых случаях.

.*

:h2.Макроопределения
:p.
Некоторые действия, которые никак не удавалось записать с помощью функций и операторов,
были записаны в виде команд, создаваемых с помощью так называемых "макроопределений" 
(это название было позаимствовано из языка Lisp, где они называются просто "macro"). 
Команды в R-5 - это, как правило, глаголы, и они работают так же, как и функции, но 
вмещают больше действий в одной команде.

:p.
Из языка Rexx была позаимствована команда "Parse" для разделения строк на слова:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Macro-1.rc'.
:font facename=default.

:p.
Нет никакой возможности записать её в виде функции, так как она в каждом случае даёт
разную последовательность вызовов нескольких функций: в примере выше за одной командой
стоит целый поисковый алгоритм, разбирающий путь к файлу - и изобретать его каждый раз 
заново будет пустой тратой времени.

:p.
Из языка Lisp было позаимствовано такое действие, как отсоединение первого элемента
от массива или списка:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Macro-2.rc'.
:font facename=default.

:p.
Записать его в виде функции не удастся, так как у него два выходных параметра, что 
недопустимо для функций, у который может быть только один выходной параметр. Тем не
менее, было обнаружено огромное количество задач, где требуется именно это действие -
и оно было записано в виде макрокоманды.

:p.
Наконец, именно для R-5 была сделана проверка параметров с выбрасыванием исключений, 
которую удалось записать в виде макрокоманды:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Macro-3.rc'.
:font facename=default.

:p.
Несмотря на то, что некоторые проверки можно задать ещё на уровне типов данных (в примере
выше параметры "X" и "Y" были заданы как целые числа, а не как целые со знаком - поэтому они 
не могут принимать значения меньше нуля), но *все* проверки добавить в описания типов никогда 
не удастся - они, как бесконечная мозаика, растут во все стороны и уходят за горизонт гораздо 
быстрее, чем растут человеческие способности к их описанию. Проще добавить в язык ещё одну
команду.

:p.
Макрокоманды и имена функций не пересекаются. Функции скрыты за командами вызова, как в 
следующем примере, что позволяет написать в программе функцию с таким же именем, как и 
название макрокоманды:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Macro-4.rc'.
:font facename=default.

:p.
Здесь "Parse()" - функция, а "Parts" - структура данных, которую она заполняет. Оператор
в виде одинарной кавычки скрывает вызов этой функции и позволяет получить от неё переменную, 
чтобы использовать её в другом выражении. В структуре "Parts" есть поле "Name" и оператор 
присваивания работает с этим полем, добавляя к нему строку. 

:p.
Как правило, названия макрокоманд и функций в программах не совпадают: в именах функций 
редко используются глаголы - а команды задаются как раз в виде глаголов, это "действия" 
по правилам языка. Так было ещё в языке Rexx, где функциям давали краткие имена, вроде 
"LineIn()", "Point()" или "Clock()", но никогда "ReadLine()", "SetPixelAt()" или
"GetCurrentDateTime()" - эту особенность Rexx унаследовал от языка PL/I.

.*

:h2.Краткая форма записи
:p.
Большинство распространённых сегодня языков программирования не имеют никакой защиты против
людей, создающих нечитаемый код - более того, многие языки (хотя и не все) даже подталкивают
их к тому, чтобы создавать плохие программы ("а зато быстро"). В таких языках, как Pascal, 
читаемость портят бесконечные метки "begin/end", в Python это отступы (придуманные, как ни 
странно, как раз для улучшения читаемости), в Java - длинные наименования классов вроде 
"AbstractSingletonProxyFactoryBean" и так далее.

:p.
Вряд ли новый язык программирования сможет запретить составлять плохие программы - но уж 
во всяком случае, он должен быть сделан так, чтобы написание легко читаемых и сопровождаемых 
программ на нём было лёгким делом. Как одно из решений, в R-5 были изменены операторы условия - 
их можно записывать не только в обычной "прямой" форме:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-1.rc'.
:font facename=default.

:p.
И не только в прямой форме в сокращённом виде:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-2.rc'.
:font facename=default.

:p.
Но и в обратной форме:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-3.rc'.
:font facename=default.

:p.
Краткая форма записи позволила сократить некоторые вычислительные действия. В качестве примера 
можно рассмотреть такое действие, как балансировка матрицы (когда элементы из правого верхнего 
угла переносятся в левый нижний угол), которое от трёх строк:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-4.rc'.
:font facename=default.

:p.
Или одной строки в прямой форме в сокращённом виде:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-5.rc'.
:font facename=default.

:p.
Было сжато до одной строки в обратной форме:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-6.rc'.
:font facename=default.

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

:p.
Даже вычисления, в которых создаются временные переменные, как в следующем примере:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-7.rc'.
:font facename=default.

:p.
Могут быть записаны в более удобном для чтения виде:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-8.rc'.
:font facename=default.

:p.
То же самое при вызове функций:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-9.rc'.
:font facename=default.

:p.
И то же самое поверх операторов-стрелок, выполняющих очистку и преобразование данных:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-A.rc'.
:font facename=default.

:p.
И даже так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-B.rc'.
:font facename=default.

:p.
И вот так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-C.rc'.
:font facename=default.

:p.
А в тех случаях, когда надо выполнить не функцию, а команду языка, ставится два 
символа "-":

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-D.rc'.
:font facename=default.

:p.
И вот так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-E.rc'.
:font facename=default.

:p.
Компилятор следит за тем, чтобы имена переменных после одинарной кавычки не совпадали
с именами ранее созданных переменных, а в случае совпадения он считает, что действие 
после кавычки выполняется с уже созданной переменной:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-F.rc'.
:font facename=default.

:p.
Кажется странным, что вычислительные алгоритмы надо читать снизу вверх - но ведь 
и вычисления со скобками мы читаем изнутри наружу. Здесь используется тот же самый
приём.

:p.
Всё то же самое удалось сделать и с циклами: во многих случаях их заголовки не оставляли 
никакой возможности понять, что же здесь происходит - но теперь кроме подробной записи с 
отступом вправо:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-G.rc'.
:font facename=default.

:p.
Появилась ещё и краткая запись без отступов:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-H.rc'.
:font facename=default.

:p.
Теперь при первом же взгляде на оператор цикла можно сразу увидеть, что он намерен делать: 
в данном случае - заменять в строке двойные пробелы на одинарные. В предыдущем примере цикл
был составлен по старым правилам, но при чтении программы она выглядит таким образом: "цикл 
будет делать что-то до тех пор, пока в строке есть хотя бы один двойной пробел". Для того, 
чтобы понять, какие переменные он изменит и что будет делать, его надо прочитать от начала 
до конца.

:p.
Поддерживаются также циклы с другими ключевыми словами:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-I.rc'.
:font facename=default.

:p.
И вот так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-J.rc'.
:font facename=default.

:p.
И даже так:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-K.rc'.
:font facename=default.

:p.
И даже циклы, закрытые условиями в прямоугольных скобках:

:p.
:font facename=Courier.
:include mode='code' file='0001-Intro\Include\Syntax-L.rc'.
:font facename=default.

:p.
Эта форма записи используется в основном в последних главах книги: примеры становятся 
более краткими, и всё меньше напоминают C и другие распространённые языки.

:p.
Помимо краткой записи, R-5 позволяет создавать циклы с несколькими счётчиками, а 
также поддерживает обыкновенную и хвостовую рекурсию. Всё это подробно разобрано в 
других главах.

.*

:h2.Правила доступа к данным
:p.
Если оставить в стороне синтаксис языка и посмотреть, что находится под ним, то 
можно увидеть исполнитель команд со сборщиком мусора. Синтаксическое дерево может 
быть выполнено "на месте" или преобразовано в байт-код или в код на языке C, что 
обычно и делается. Казалось бы, ничего нового, но правила, по которым байт-код 
выполняет действия с данными, отличаются от таких же правил в других языках.

:p.
Прежде всего, в языке R-5 нет глобальных переменных - нет ни в какой форме, как 
на уровне байт-кода, так и на уровне синтаксиса языка (где их место занимают описания 
функций и типов данных, а также их краткие описания - "переходники"). Таким образом, 
если переменные и структуры данных доступны в какой-то одной части программы, то можно 
быть уверенным в том, что они не будут доступны в других частях программы без особого 
на то разрешения.

:p.
Как и большинство функциональных языков, R-5 препятствует созданию изменяемого 
состояния, закрывая содержимое переменных от дальнейших изменений, как только они 
были заполнены. Это даёт уверенность в том, что данные не будут случайно изменены, 
а кроме того, позволяет разделить программу на два потока в любой точке, где и как 
только это потребуется. Как и другие языки, R-5 умеет "запечатывать" переменные, но 
делает это при возврате из функции. В нём есть возможность оставить некоторые данные 
открытыми на изменение и удаление в дальнейшем, но поведение по умолчанию - закрытые 
от изменений.

:p.
При этом, R-5 не знает и такой "удобной" вещи, как скрытое состояние - источник 
нескончаемой головной боли у программистов, пишущих на Java, Python, Object Pascal 
и других языках. Скрытое состояние - то же самое, что и глобальное состояние, но 
теперь данные оказываются запрятаны в "объектах", доступ к которым осуществляется
с помощью ссылок... и ссылки бьются и остаются незаполненными, а в полях объектов
неизбежно накапливается мусор. Ко всему прочему, спрос на многопоточные программы 
привёл к тому, что нам теперь приходится бороться ещё и со взаимными блокировками: 
они возникают, как только два потока пытаются получить доступ к нескольким объектам 
в произвольном порядке, например, "ABCD" в одном потоке и "DCA" в другом.

:p.
Как оказалось, эти препятствия можно обойти, если собрать все данные в общее дерево 
(или несколько деревьев), задав права доступа для каждой из его веток. Так как описания 
типов данных располагаются в разных пространствах имён, то и работать с ними будет только 
код из того же пространства имён, где описаны их типы. Точно так же, как в ООП, но теперь, 
с точки зрения программиста, скрытых данных в программе не будет: во время отладки всё 
дерево может быть распечатано в любой точке программы. Существует также несколько правил, 
согласно которым осуществляется доступ к данным, описанным в других пространствах имён - 
в том числе и через дополнительную прослойку в виде функций-переходников. Но оставить в 
программе скрытое состояние теперь не удастся - даже намеренно.

:p.
В языке есть и ещё один запрет: не размножать ссылки на данные. R-5 не позволяет 
создавать несколько ссылок с доступом на изменение на одну и ту же переменную или 
структуру данных - и для того, чтобы создавать их, данные вначале должны быть закрыты 
от изменений. О размерах жутковатого "ссылочного навеса" над структурами данных в 
современных языках говорит хотя бы тот факт, что наиболее часто возникающая ошибка 
в программах - доступ по неверному указателю. Здесь она появляется не чаще других 
ошибок, так как в R-5 все переменные на протяжении всего времени выполнения программы 
имеют какое-то значение, и его можно прочесть: нет "пустых ссылок", есть незаполненные 
переменные, содержащие пустые значения, и к ним возможен доступ на чтение.

:p.
Ко всему прочему, в программах R-5 крайне редко встречаются структуры данных, 
поля которых были бы ссылками на другие структуры - вместо них в большинстве 
случаев создаются вложенные (а не связанные) структуры, а также массивы структур. 
То есть, "связывание данных на одном уровне" было заменено на "расположение данных 
в виде дерева в виде нескольких уровней". Найдётся не так уж много алгоритмов, которые 
нельзя было бы написать без ссылочного типа данных, на одних только структурах, массивах 
и списках, точно так же, как найдётся не так уж много алгоритмов, для написания которых 
обязательно требовались бы операторы перехода и номера строк. Ссылочный тип в R-5 есть,
но скрыт за синтаксисом языка.

:p.
Отсутствие ссылок в структурах данных (по крайней мере, в большинстве случаев) 
означает и отсутствие циклических зависимостей, когда "объекты" с "методами" в 
них, связанные вроде бы по цепочке, образуют петли вида "ABCA" или "A(BA)C" 
и так далее. В таких условиях можно упростить сборщик мусора, которому теперь не 
надо распознавать циклические зависимости - так что он может просто освобождать 
память на возврате из функции, и всё.

:p.
В дополнение к сборке мусора, R-5 умеет выполнять сжатие области памяти, в которой 
хранятся структуры данных. Если программа переходит к ожиданию сообщения или другого 
внешнего события, и ей на вход ничего не поступает (в очередях сообщений ничего нет,
ни в одном потоке), она начинает передвигать данные ближе к началу занимаемой ими 
области, располагая их там, где ещё есть свободное место (и в любом случае, даже 
получая сообщение, она передвигает хотя бы одну область памяти). Постепенно "куча"
("heap") уплотняется настолько, что больше передвинуть ничего не удаётся - и тогда 
сжатие прекращается.

:p.
Какова же расплата за добавленные ограничения? Прежде всего, вычисления на списках 
никогда не позволят достичь того же быстродействия, как вычисления на регистрах и 
указателях, как в языке C: здесь требуется больше прыжков по оперативной памяти, а
вместе с тем происходит и больше промахов кеша процессора, и больше тактов процессора 
тратится впустую. А кроме того, составление программ на R-5 занимает больше времени, 
чем на Java и Pascal: общее дерево с данными надо проектировать, и на это уходит время. 

:p.
Зато их легче отлаживать и читать.

.*

:h2.Другими словами
:p.
:artwork align='center' name='0001-Intro\Images\Spacecats.bmp'.