|
|
|
Введение |
Важные синтаксические особенности: |
||
Один класс - один модуль
|
||
Двойное именование типов, переменных, функций, констант
|
||
Классы, перечисления и записи всегда упоминаются в фигурных скобках
|
||
Ограничение длины строк кода
|
||
Правило продолжения оператора на другую строку
|
||
Возможность вызова функции в постфиксной форме для статических однопараметрических функций
|
||
Массивы всегда упоминаются с квадратными скобками: A[ ]
|
||
Строка кода содержит только один оператор
|
||
Ограничения на качество кода:
|
Перегрузка операторов
|
В языке отсутствуют: |
||
Препроцессор
|
||
Указатели функций
|
||
Массив как результат функции
|
||
Множественное наследование
|
||
Оператор go to
|
||
Символьный тип данных
|
||
Указание разрядности типов данных
|
||
Неявные преобразования разнородных типов данных
|
||
Обработка исключений
|
I. Синтаксис операторов |
I. 1. Форматирование операторов |
I. 1. a. Один оператор - одна строка |
Простые операторы не требуют завершения специальным знаком (таким, как ' Знак ' Например:
|
Строка не может быть длиннее 80 символов (не учитывая комментарии до конца строки и пробелы и табуляции в конце строки). Символ табуляции считается за один символ. Оператор может быть записан в нескольких строках, но строка считается продолжающейся на следующую только если:
|
Другой способ запомнить правило переноса: строка считается продолжающейся на следующую только если
|
Или использовать иллюстрацию ниже:
|
Для упрощения чтения кода, содержащего длинные строки с переносами, рекомендуется отделять такие строки от соседних в блоке пустыми строками. (Компилятор выдает такую рекомендацию в виде предупреждения). |
I. 1. b. Блочные операторы |
Блочные операторы создают вложенный уровень операторов. Блок вложенных операторов завершается символом ';'. Функции и другие блоки уровня класса завершаются символом '.' (точка). А именно: заголовок класса, список импорта, определение типа перечисления, определение блока констант. Строка не может завершаться двумя и более подряд одинаковыми символами завершения ';' или '.'. Но сочетание ';.' для завершения последней блочной конструкции в функции и самой функции допускается. Если завершения требуют более двух блоков операторов, то символ завершения для внешнего блока будет находиться на отдельной строке. Например: |
FOR i IN [1
TO 100] :
|
Имеется только одно ключевое слово для условного оператора ( Все прочие операторы являются простыми: |
Компилятор требует помечать маркером
|
I. 1. c. Комментарии |
Иллюстрация:
|
|
I. 1. d. Регистрозависимость для идентификаторов |
|
Имена типов образуют особое пространство имен, не пересекающееся с прочими именами (переменных, констант, функций, процедур, модулей).
|
|
|
Например, A и a - это разные переменные (или константы). Имена Публичных полей, функций, параметров функций начинаются с Прописной буквы. Члены класса, имена которых начинаются со строчной буквы, локальны в классе (но доступны в его наследниках). Локальные переменные функций рекомендуется именовать со строчной буквы, параметры функции - с прописной.
|
I. 1. e. Именование |
При декларации переменной, функции, типа данных, элемента перечисления, таблицы - ее длинное имя может быть разделено на части символом '|'. Первая часть - это краткое имя. Так же, символом '||' от первой цепочки именования может быть отделена вторая цепочка, и так далее. Единственное требование: все цепочки должны начинаться с той же буквы (без учета регистра).
При этом:
|
Имена функций, переменных, полей классов и структур, таблиц, и именованных констант - это идентификаторы, начинающиеся с буквы. Имена {Классов} - идентификаторы, заключаются в фигурные скобки и начинаются с прописной буквы. Имена {структур} и {перечислений} так же идентификаторы в фигурных скобках, но именуются со строчной буквы. Имена элементов перечислений записываются в апострофах. Так как это константы, то рекомендуется для них использовать КАПИТАЛИЗИРОВАННЫЕ имена. |
I. 1. f. Модификаторы |
Многие декларации языка (заголовок модуля, оператор, декларация переменной или типа данных) могут иметь модификаторы.
Например, в заголовке класса:
|
Модификаторы не воздействуют на основную семантику кода. Они лишь помогают компилятору в обеспечении большей надежности / оптимальности по быстродействию / размеру кода и т.п. Если в готовой программе, не содержащей ошибок, убрать все модификаторы (полагая, что в языке они не требуются), это (обычно) не изменит результат работы программы (но может повлиять на размер кода и скорость работы в сторону увеличения или уменьшения).
В некоторых случаях в качестве модификаторов используется наличие некоторого особого идентификатора в составе имени переменной (в любом регистре). Например, слово dummy в составе имени предотвращает выдачу компилятором предупреждений о том, что данная переменная или параметр не используется в коде. Слово temp в имени сообщает, что локальная переменная временная, и нет необходимости предупреждать программиста о том, что присвоенный ей создаваемый объект не будет существовать по окончании работы функции. |
I. 2. Оператор присваивания |
I. 2. a. Простой оператор присваивания |
где |
|
Для сравнения на равенство двух операндов используется си-подобный оператор |
I. 2. b. Операторы присваивания в комбинации с арифметической, логической или поразрядной логической операцией |
Дополнительные операции |
I. 2. c. Операторы отправки данных |
Операция
|
Аналогичная операция
Справа от оператора >> может находиться декларация новой переменной.
|
I. 2. d. Операторы повторного присваивания и отправки данных |
Если оператор начинается с символа Для такого повторного присваивания (или отправки данных):
|
I. 3. Выражения |
|
I. 3. a. Операции проверки наличия элемента |
Операторы
В случае конструируемого массива, список значений должен содержать только константы. В этом случае, когда тип проверяемого значения - строка, не допускается конструировать массив из единственного элемента. Либо справа должна быть строка, а не массив. Операция IN / !IN не применима к паре вещественное число - вещественный массив (так же как запрещено сравнение на равенство значений типа REAL).
|
I. 4. Прочие простые операторы |
|
|
I. 5. Условный оператор CASE |
Оператор По исполнении любой ветви всегда происходит выход из всего оператора
|
Классический пример - решение квадратного уравнения в области вещественных чисел: |
|
||
Особый вариант оператора Синтаксически такой вариант оператора |
|
Так же, имеется особый вариант оператора |
I. 6. Операторы цикла FOR |
Оператор цикла
|
|
Для организации неконтролируемого бесконечного цикла используется блочный оператор
|
Переменная цикла, если она целочисленная, может (как и любая целочисленная переменная) получать атрибут |
В случае завершения блока оператора
|
Оператор |
I. 6. a. О возможности присваивания значений переменным цикла:
|
I. 7. Блок операторов PUSH |
Предназначен для гарантированного сохранения некоторой переменной или поля с одновременным присваиванием ему нового значения на время выполнения блока, с последующим гарантированным восстановлением значения этой переменной или поля по окончании исполнения блока. Либо для вызова специального PUSH-метода, с обязательным вызовом соответствующего ему POP-метода при выходе из блока PUSH.
Восстанавливающие действия гарантируются в том числе:
Синтаксис:
|
||||
|
||||
В операторе Например:
|
||||
|
I. 8. Блок операторов DEBUG |
Предназначен для временной инъекции кода, который требуется только для целей отладки. Внутри этого блока не ведётся подсчёт и контроль уровней вложенности блоков. Компилятор всегда выдаёт предупреждение о наличии таких блоков с тем, чтобы программист не забыл удалить их из кода (или закомментировать) по окончании отладки. Внутри отладочных блоков могут быть декларированы локальные переменные, но использовать их можно только опять же внутри отладочных блоков (хотя и не обязательно только в том блоке, в котором они декларируются).
|
Если для правильной компиляции блоков |
Для оператора
|
I. 9. Блок операторов SILENT |
Предназначен для предотвращения выдачи компилятором предупреждений в некотором участке кода. Например, предупреждений о наличии отладочных блоков DEBUG: |
I. 10. Блок операторов LIMIT |
Предназначен для ограничения времени выполнения некоторого кода: |
Варианты заголовка:
|
Проверки на возможное превышение заданных ограничений производятся обычно 1 раз на каждой из 65535 итераций циклов, выполненных в коде AL-IV. Поэтому финальное превышение времени или другого заданного параметра может превышать заданное на эти самые 64К итераций циклов, выполнившихся между проверками. В случае превышения заданного ограничения выполнение кода в пределах блока прекращается, и выполнение продолжается со следующего за блоком оператора. При этом, если выполнялись какие-то блоки PUSH, то они гарантированного завершаются соответствующей им операцией POP (например, восстановлением значения переменной). |
I. 11. Оператор LIKE |
(Не путать с операцией LIKE в выражении!)
Предназначен для вставки ранее написанного кода в новой позиции. Вставляемый код должен быть расположен между двумя блочными комментариями (на одном уровне вложенности). Метка первого блочного комментария (в совокупности с именем функции) используется для указания того, какой именно блок кода следует повторить. Имеются правила:
|
||||
|
||||
|
Дополнительно, при использовании оператора
Списки замен заключаются в скобки и перечисляются через запятую. Замена должна иметь множитель в форме Все замены выполняются непосредственно перед компиляцией оператора LIKE, на участке кода, который подставляется вместо LIKE. И образец, и строка, на которую он заменяется, может быть заключен (или не заключен) в апострофы. Только строка справа от знака ==> может быть пустой, образец должен содержать хотя бы один символ.
|
И, пожалуйста, помните:
Поэтому не злоупотребляйте использованием |
I. 12. Оператор REVERT |
Предназначен для вставки ранее написанного кода в новой позиции с переворачиванием направлений присваивания. Переворачиваемый код должен быть расположен между двумя блочными комментариями (на одном уровне вложенности). Метка первого блочного комментария (в совокупности с именем функции) используется для указания того, какой именно блок кода следует повторить. Имеются правила:
|
Пример: |
|
II. Переменные, константы и типы данных |
II. 1. Простые типы данных |
II. 1. a. Встроенные простые типы данных |
Простые (встроенные) типы данных (которые не могут быть переопределены):
|
|
|
|
|
|
Для типов данных разрядность не задаётся.
|
При использовании байтового типа в классе, он должен быть помечен в заголовке модификатором |
II. 1. b. Запись констант базовых типов данных |
|
|
|
|
|
|
|
II. 1. c. Перечисления |
Перечислимый тип данных определяет набор именованных констант. Сам набор так же именуется для того, чтобы на него можно было ссылаться.
|
ENUM {color|s_of_traffic_light} :
|
Операции над значениями перечислимых типов данных:
|
Перечисление может использоваться как диапазон индексов фиксированного массива при его декларации:
В этом случае в качестве индексов этого массива могут использоваться переменные и константы
соответствующего перечисления:
|
Элементы перечисления считаются неупорядоченными, и не могут сравниваться операциями <, <=, >,
>= (применимы сравнения == и !=). Из элементов перечисления может быть сформирован константный массив, и
для пары элемент - массив элементов допустима операция В случае конфликта имён перечислимых элементов, они обязаны квалифицироваться именем перечисления в
форме:
В случае совпадения имён самих перечислений, в квалификацию должен включаться класс, из которого это
перечисление родом:
|
При использовании в операторе
|
II. 2. Переменные, массивы |
II. 2. a. Декларация переменных |
Декларация переменной начинается с указания ее типа данных в {фигурных} скобках (или
одного из зарезервированных имён типов
Переменной всегда присваивается начальное значение. Если такое значение не присвоено явно, присваивается значение по умолчанию.
|
Правила именования переменных: |
|
Регистр букв имён переменных:
|
II. 2. b. Модификаторы полей |
Если переменная требует модификаторов, они записываются в декларации вслед за именами переменной и её размерностями. |
|
Кроме явно указываемых выше модификаторов
|
II. 2. c. Декларация именованных констант |
Константы декларируются только на уровне класса, и только встроенных простых типов (
Рекомендуется использовать капитализированные имена констант (все буквы в верхнем регистре). Блок констант может иметь имя (задается в фигурных скобках после типа констант). Имя блока констант может использоваться при задании ограничений на значения параметров функций. |
II. 2. d. Декларация массивов |
После имен переменной, являющейся массивом, в квадратных скобках записывается размерность.
|
Начальное значение для массивов обеспечивается обязательно, как и для всех остальных переменных:
|
II. 2. e. Конструктор массива |
Конструктор массива - это перечень элементов массива в квадратных скобках в виде: В качестве значений попускаются только константы. |
Конструктор массива может использоваться как второй операнд операции проверки на вхождение |
II. 2. f. Использование массивов |
Основные операции с массивами:
Передача массива как параметра в функцию:
Не допускается:
|
Особое индексирование элементов массивов (и символов строк) значением '*':
|
II. 3. Функции |
II. 3. a. Заголовок функции |
FUNCTION имена (параметры)
==>
тип_результата , модификаторы :
|
|
|
|
|
|
|
|
Параметры перечисляются через запятую.
|
Для параметра-массива после имени указывается размерность в квадратных скобках.
|
Целочисленные параметры могут иметь атрибут |
Параметры не могут иметь модификаторы. Параметры, которые не используются, должны иметь слово dummy (в любом регистре) в качестве части своего имени. Скалярные параметры всегда принимаются по значению, и не могут изменяться в теле функции.
|
Параметры могут иметь ограничения на значения или участвовать в ограничениях, которые задают возможные
списки и диапазоны константных значение параметров - безусловно, либо в зависимости от значений других
констант. (См. модификаторы |
Для операторов, параметрами являются типы данных. Как минимум, один из типов данных должен быть классом или структурой. В теле оператора (представляющим собой выражение) для ссылки на параметры используются буквы A и B, хотя в заголовке оператора эти буквы не пишутся. Буква A соответствует первому операнду, B - второму. В случае переопределения унарной операции "-" для ссылки на единственный операнд используется имя A. |
В случае обобщенных функций в позиции типа параметра размещается перечисление из нескольких типов,
заключенное в фигурные скобки, например: |
|
Если тип результата не указывается (вместе со стрелочкой '==>'), то функция не возвращает результат.
|
|
Например, подсчет символов точки в строке:
|
В случае обобщенных функций тип результата так же может быть списком типов, заключенных в фигурные
скобки: |
|
Допускается после типа возвращаемого результата запись вида:
|
|
|
Модификаторы функции перечисляются через запятую. Возможны модификаторы: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
В случае, если в теле функции используются переопределенные операторы, то (независимо от вида функции -
|
II. 3. b. Тело функции |
Тело функции состоит из операторов, и завершается символом '.' (точка).
|
Если обозначенные выше ограничения не соблюдены, в заголовке класса требуется указывать модификатор
|
В случае единственного оператора присваивания значения выражения псевдо-переменной |
II. 3. c. Вызов функций |
Круглые скобки требуется использовать только при наличии параметров.
|
III. Классы и объекты |
III. 1. Классы |
III. 1. a. Декларация класса |
Синтаксис.
В одном файле располагается декларация одного класса. Все прочие декларации (перечислимые типы, функции, константы, поля) существуют только в пределах классов. Глобальных (статических) полей классов не бывает, все поля являются членами каких-либо экземпляров классов.
|
|
|
III. 1. b. Модификаторы класса |
Модификаторы для класса записываются после имен класса, через запятые. Имеются модификаторы:
|
III. 1. c. Секция импорта |
Первыми в классе после заголовка должны быть указаны оператор
(В качестве завершения блока IMPORT может быть точка или точка с запятой).
Операторы
|
III. 1. d. Наследование |
Для указания предка класса, первым в классе после операторов
|
||||
При переопределении метода в классе:
Переопределённый метод может вызывать базовый метод (одноимённый метод родительского класса).
|
III. 1. e. Объекты. Сильные и слабые ссылки |
Переменная класса (экземпляр класса) является объектом класса.
|
ПРАВИЛО
|
|
III. 1. f. Поля |
Поля декларируются в классе так же, как и локальные переменные в функции, но на том же уровне, что и функции, методы и другие декларации класса.
Декларации поля (схема):
|
|
Поля класса могут иметь модификаторы, перечисляемые после декларации поля через запятые (но до инициализации константой, если она присутствует). |
|
III. 1. g. Методы |
Декларацию методов, в отличие от статических функций, начинает ключевое слово
|
III. 2. Работа с объектами классов |
III. 2. a. Оператор создания экземпляра |
Конструкция объекта:
|
III. 3. Другие операторы уровня класса |
Если класс имеет предка в иерархии, он должен быть указан оператором |
Завершается класс оператором |
До оператора
=инициализация
|
III. 4. Завершение класса. История изменений. Массив DATA[]. |
Класс завершается оператором |
Если директива Содержимым блока являются сообщения в форме:
Последнее сообщение блока изменений должно завершаться точкой, или состоять из одной только точки. |
История изменений может завершаться вместе с концом текста. Но если кроме истории изменений текст
после директивы Например:
|
IV. Структуры (STRUCTURE) |
IV. 1. Декларация структур |
Синтаксис.
Структуры декларируются внутри классов. Имя структуры всегда начинается со строчной буквы. Имя структуры может делиться значком '|' на части: часть до первого знака является кратким именем. Полное имя не должно быть короче 8 символов. Все декларации структур в классе всегда доступны для использования в любых классах, использующих этот класс.
Структура состоит из:
Декларация структуры завершается точкой.
|
'
|
Структура, как и класс, может содержать поля любого типа. Но имеются ограничения на объекты классов:
Если же поле класса имеет тип структуры, то в этом случае оно само не может быть слабой ссылкой (т.к. любая переменная или поле типа структуры является ее единственным владельцем). |
|
Все структурные переменные и поля автоматически инициализируются присваиванием полям NONE-значений (для чисел - это нули, для строк - пустые строки, для объектов классов - NONE). NONE-значение так же может быть получено для структуры при чтении из массива за пределами доступного диапазона индексов. |
IV. 2. Работа со структурами |
Структура - это класс без методов, имеющий всегда только одну ссылку на него. Поэтому при создании экземпляра
структуры нельзя использовать модификатор |
Если одной структурной переменной присваивается значение другой структурной переменной, то при этом к
переменной в правой части присваивания должна быть применена встроенная функция-метод
|
STRUCTURE
|
Такой же конструктор может использоваться при передаче фактического параметра функции в позиции параметра типа структуры. При присваивании структуры ее содержимое просто копируется. |
При передаче структуры в качестве параметра, она может использоваться в вызванной функции только для чтения, в том числе нельзя изменять значения ее полей. Это отличается от правил работы с объектами, для которых поля могут быть изменены . Соответственно, при присваивании значения всей структуры-параметра, может (и должен) использоваться
только псевдо-метод |
Структура может быть возвращена как результат функции. При работе с псевдо-переменной
Структуры не могут передаваться в качестве параметра или результата нативных (низкоуровневых) функций. |
Структура может быть создана обычным для объектов оператором создания структуры:
|
Если цикл |
Существует возможность присваивания структур разных типов, имеющих одноименные (и однотипные, или
совместимые по типам, поля) :
В левом списке При присваивании разнородных структур псевдо-функции |
Структурные переменные могут использоваться при работе с базами данных, в сочетании с операторами SQL ( |
IV. 3. О реализации структур в конечной программе |
Не должно быть никаких допущений насчет того, как поля структур располагаются в оперативной памяти во время работы программы, или об их порядке или выравнивании (на границы машинных слов). То же касается размеров структур в памяти, и способах размещения их в памяти. Так же, предположение о большей (или меньшей) эффективности структур могут оказаться полностью неверны. Структуры могут быть фактически реализованы как объекты, или для простых структур, не содержащих строк, динамических массивов и ссылок на объекты, могут быть реализованы именно как структуры в целевом языке. Все, что действительно нужно знать о структурах - это то, что структура хранится как простая переменная, при присваивании копируется как переменная (например, поле за полем). На них нет возможности сослаться указателем (хотя при передаче в качестве параметра используются именно указатели - но поля структуры предназначены только для чтения). Требование использовать функции CLONE / DISMISS введено для того, чтобы программист чаще обращал внимание на то, что данные структуры при присваивании именно копируются, и оригинальная структура не будет изменена при изменении полей принимающей структуры. Это уменьшает количество ошибок в программе. |
V. Тестирование |
V. 1. Основные положения |
Класс может содержать особые функции, которые начинаются ключевым словом
|
Тестированию подлежат:
Тест считается покрывающим, только если все подлежащие тестированию строки кода выполнялись при
тестировании класса хотя бы один раз. Если это условие не выполнено, класс должен быть помечен как |
Все секции функции |
Тестированию не подлежат:
|
Однако, при тестировании класса, унаследованного от абстрактного, все не переопределённые методы его абстрактного предка должны быть протестированы, чтобы сам класс считался протестированным. Допускается в абстрактном классе поместить тестирующие функции с параметрами, предназначенные для тестирования всех или части функций абстрактного класса. Тесты с параметрами не выполняются автоматически, но могут быть вызваны из других тестирующих функций. В частности, если создать тест(ы) с параметрами внутри абстрактного класса для тестирования его методов, то эти тесты могут быть вызваны в унаследованных классах для упрощения тестирования кода абстрактного предка.
|
Тестирование выполняется каждый раз при компиляции проекта (кроме случаев, когда результаты предыдущего успешного тестирования сохранены, и не изменился код, от которого они зависят, либо в опциях проекта для компилятора тестирование запрещено ключом /$NOTESTS - но это зависит от компилятора). При кроссплатформенной компиляции в некоторые целевые платформы (Java/Android) тестирование не выполняется на этапе компиляции, но со специальным ключом может быть отдельно собрано (консольное, или - псевдо-консольное) приложение для целевой платформы, специально для целей тестирования, работа которого как раз состоит в выполнении тестов. Интеграция результатов тестирования в цикл работы по компиляции приложения в этом случае невозможна. В случае кросс-компиляции для платформы Linux, тестирование кода возможно на исходной платформы. Но следует учесть, что достоверность тестов в таком случае так же не 100% (платформы все-таки отличаются, и одинаковый код на финальной платформе может в некоторых случаях работать по-разному). Впрочем, кросс-платформенная компиляция для Linux выполняется (обычно) только для самого компилятора, после чего должен работать откомпилированный и собранный компилятор на платформе Linux.
|
V. 2. Синтаксис |
Функция тестирования начинается заголовком, в котором слово |
Тестирующие функции могут иметь параметры, но такие тесты не вызываются автоматически: они могут быть вызваны только из других тестирующих функций. |
Если для функции тестирования требуются классы, не перечисленные в директивах |
Как и другие функции, тестирующая функция разбивается на секции блочными комментариями
Но для тестирующих функций имеется дополнительное требование: секция должна содержать как минимум один
оператор |
Оператор |
Оператор |
VI. Встроенная поддержка SQL- запросов |
VI. 1. Кодирование SQL запросов |
Если в классе определён метод В случае класса
|
VI. 2. Структура таблиц БД, оператор TABLE |
При установке текста SQL, если текст строкового выражения начинается с одного из ключевых слов |
|
Такие SQL-запросы ссылаются на таблицы, декларируемые утверждениями |
|
STRUCTURE {abiturient}:
|
VI. 3. SQL- подобный синтаксис |
Запросы SQL-подобны, но их синтаксис несколько изменён по сравнению со стандартом SQL:
|
VI. 4. Выполнение запросов INSERT, UPDATE, DELETE |
Запросы Для получения идентификатора вставленной записи следует использовать метод
Аналогично, для получения количества измененных/вставленных строк, следует вызывать метод
При вставке записей оператором
При этом возможно пропустить определенные поля, имена которых перечислены в списке строк:
|
VI. 5. Получение результатов SELECT |
Для получения результатов запроса SELECT:
Для приема результатов:
|
VI. 6. Транзакции |
Транзакции реализованы через PUSH-методом Transaction. Mетод
Transaction должен быть вызван в блочном операторе Если выполнение успешно дошло до ';', завершающей блок, то далее, в зависимости от
того, был вызван метод Чтобы программист "не забыл" вызвать метод Commit в теле блока транзакции, метод
|
VI. 7. Синтаксические диаграммы |
Ниже приводятся синтаксические диаграммы для операторов, формирующих SQL- запросы: |
|
|
|
![]()
|
![]()
|
![]()
|
![]()
|
VII. Дополнительно |
VII. 1. Локализация строковых ресурсов |
AL-IV поддерживает механизм локализации строк с помощью псевдо-функций вида _идентификатор. Для строки
это выглядит как вызов функции, например,
Но вызовом функции данная конструкция не является. Она лишь сообщает компилятору о том, что строку "Red square" следует поместить в массив локализуемых строк, индекс строки в этом массиве запомнить и использовать для извлечения строки из этого массива. Фактически, при этом может быть извлечена другая строка, записанная в этот массив вместо исходной строки "Red square" в результате работы функций локализации. Например, это может быть строка " Красный квадрат ". Все имена таких строковых ресурсов должны быть уникальными в пределах класса. В качестве стандартного API для управления локализацией предлагается класс |
При использовании класса Метод |
При обращении к методу Localize первым делом вызывается метод |
Местом хранения языковых файлов по умолчанию являются либо директория, в которой запускается приложение,
либо (если запись туда невозможна) - специальная директория для данных приложения. Либо, имеется возможность
явно указать такую директорию (метод |
Важно, что если в процессе разработки были добавлены новые транслируемые строки, то они распространяются
не только на исходный файл, сохраняемый из приложения при вызове |
VII. 2. Локализация ключевых слов языка |
AL-IV поддерживает возможность трансляции ключевых слов самого языка с использованием любого другого письменного языка. При этом частично используется техника локализации строк (см. выше). Все ключевые слова канонической (английской) версии языка размещаются в текстовом файле Default_.lng в директории с исходными текстами компилятора. Достаточно скопировать этот файл и переименовать, например, в Klingon_KL.lng, после чего заменить строки на свои, и становится возможно использовать ключевые слова на соответствующем языке. Ключевые слова в языковом файле имеют имена, начинающиеся буквой 'K', и в основном сосредоточены в секции [{Translation_to_canonical_keyword}]. Для использования в классе национальных ключевых слов, класс должен начинаться со спецификации языка вида ['KL'] или [Language= 'KL'], после которой первое же ключевое слово должно быть записано уже на указанном языке. Например: |
['RU'] КЛАСС {Привет_мир}, НЕТЕСТИРОВАН:
|
В связи с тем, что язык перевода может содержать ряд морфологических особенностей (падежи, спряжения, связки, предлоги и т.д.), специально для перевода ключевых слов разработаны правила, позволяющие более гибко сопоставлять более одного национального варианта для каждого ключевого слова, и даже использовать два отделенных пробелами идентификатора вместо одного ключевого слова. Для этого в качестве перевода может использоваться более одного словосочетания,
при этом словосочетания разделяются запятыми. Внутри словосочетания (которое может быть одним словом)
вертикальный разделитель разделяет несколько возможных окончаний, которые могут продолжить основной корень.
Например,
- позволяет использовать вместо THIS слова и словосочетания:
Примечание: в языке AL-IV ключевое слово
|
Вместе с ключевыми словами локализуются кодированные символы ( |
['RU']
|
Теперь достаточно включить такой класс в список импорта, и использовать переведённые наименования его функций, методов, полей и т.д. - с использованием национальных букв/ иероглифов/ рун/ литер/ клиньев/ каракулей/ узелков и т.п. |
Примечание для русскоязычных читателей. Возможность по русификации (или точнее, произвольной локализации) предоставляется как механизм, позволяющий развивать навыки программирования в любом возрасте, без необходимости начинать с изучения английского языка. Несмотря на довольно большой список слов в словаре, основа языка АЛФОР требует значительно меньше важных ключевых слов для того, чтобы можно было начать писать свой код или понимать уже написанный. Например, класс для вычисления вещественных корней квадратного уравнения: |
['RU'] КЛАСС {Квадратное_уравнение}, НЕТЕСТИРОВАН:
|
Формат класса для перевода на другой язык, в форме диаграммы:
|
VII. 3. STORE - скрытые параметры |
Модификатор STORE для метода создаёт скрытый (для вызывающей стороны) целочисленный параметр, значение которого сохраняется на стороне вызывающего объекта. В модификаторе задаётся имя параметра, как его видит функция, и может быть задано первоначальное значение:
|
|
Для каждого вызова метода в вызывающем классе создаётся скрытое целочисленное поле для параметра, и это
поле передаётся в метод по ссылке неявным образом. Передача по ссылке означает, что если метод изменяет
значение |
|
Для того, чтобы "забыть" сохранённые значения параметров, может использоваться вызов метода,
имеющего модификатор
|
|
Сочетание модификаторов Пример реализации доступа к колонкам listview по именам:
|
|
|
|
В данном примере, модификатор |
VII. 4. Отменённые и устаревшие классы, структуры, перечисления, поля, функции |
По мере развития классов и библиотек классов, авторы могут приходить к необходимости переименовывать какие-либо вещи, какие-то начинают устаревать, и их поддержка начинает дорого обходиться, какие-то замещаются новыми, какие-то просто прекращают существовать. Чтобы иметь возможность управлять на уровне языка отмиранием ненужных старых
возможностей, и обеспечивать плавный переход к использованию в новых версиях продукта только новых
возможностей, в язык введены модификаторы
|
Второе применение модификаторов Например, при создании класса К сожалению, сообщение об ошибке от компилятора не будет получено в том случае, если программист присвоил
свою форму класса |
VII. 5. Ограничения на значения параметров |
Функция может иметь модификаторы
|
Безусловное ограничение имеет форму:
|
Условное ограничение имеет форму:
или
|
зачем это может понадобиться?
Например, для реализации набора переходников к библиотеке OpenGL. Можно упростить работу, просто собрав переходники к соответствующим функциям, и передавать так же целочисленные константы, но добавить ограничивающие модификаторы, чтобы обеспечить проверку на недопустимые наборы значений параметров. Это намного проще, чем строить системы классов или использовать для "чистоты" перечисления, и обеспечивает тот же уровень защиты (если не лучший). И при этом работают классические примеры (того же NeHe), практически без изменений (достаточно убрать символы ';' в конце операторов). |
VII. 6. Контроль зацикливания |
|
VII. 7. Оптимизация кода. INLINE- вставки |
|
VII. 8. Оптимизация кода. UNROLL ( раскрутка) для циклов FOR |
|
VII. 9. Синтаксический сахар |
a. Если имеется несколько подряд присваиваний (или добавлений в строку или в массив) одному и тому же
получателю, то получатель в очередных операторах может быть заменен символом.. (две точки). При этом, в
случае массива, квадратные скобки вслед за точками опускать нельзя. Например:
|
b. Если целью был объект, то дальнейшие обращения к его полям могут заменяться тремя точками:
|
c. Имеется возможность в случае присваивания полю, указанию которого предшествует цепочка разыменований
(например, A.B.C(params).D[index].E), также указать, какое поле будет считаться целеприемником при
последующих продолженных присваиваниях/добавлениях. Для этого вместо символа точки в соответствующей позиции
(после интересующего поля, заменяемого далее удвоенной точкой) употребляется троеточие. Например:
|
d. Если в пределах одного выражения встречается несколько подвыражений вида A.B[index].C(params).D, и
далее цепочка повторяется, и только финальное поле отличается, то второе и последующее подвыражения
могут быть заменены на .E, .F и т.п. При этом лидирующие знаки -, !, ~ не относятся к выражению, и их не
следует опускать. Например:
e. В операторах
f. В операторах вывода в консоль (
g. Функция, возвращаемый результат которой определяется единственным выражением, может записываться в
краткой форме:
(Пробел между ':' и '=' не обязателен, допускается ':=' ) .
|
VII. 10. Краткая справка по "встроенным" функциям |
Причина, по которой существуют такие функции: невозможность для них в рамках языка строго описать параметры/ результаты. Например, на уровне синтаксиса языка запрещено задавать параметр как "массив из элементов любого типа" . В то же время, удобно иметь набор одинаково поименованных функций для работы с любыми массивами.
Примечание. С введением "перегрузки" функций такая причина часто может быть нивелирована, хотя по-прежнему есть проблема с описанием параметров вида "структура любого типа" или "любое перечисление": AL-IV не предусматривает таких обобщений на уровне языка.
Поскольку все такие функции являются статическими, они могут вызываться как в классическом варианте foo(x), так и в префиксном x.foo.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Все встроенные функции могут идентифицироваться полностью капитализированными именами, например: A[].COUNT |
VII. 11. Обобщенные функции |
Обобщенные (или иначе - перегруженные) функции - это функции с переменным набором типов данных параметров (и, возможно, результата).
Тип данных параметра (и, возможно, результата) может быть заменен списком типов параметров в фигурных скобках. Например: |
FUNCTION Min|imum_of_two_values(
|
Правила:
1. Только статические функции могут быть обобщенными.
2. Только результат не может иметь вариантный тип - как минимум один параметр должен быть вариантного типа.
3. Все параметры (и если результат вариантного типа, то и результат) должны иметь одинаковое число вариантов. Порядок вариантов важен, и все типы с одинаковым индексом образуют один набор параметров (и результата, если результат вариантного типа).
4. Первый параметр с вариантным набором типов должен иметь все различные типы в списке. С каким именно набором параметром обобщенная функция вызывается, определяет тип первого параметра с вариантным типом. |
В теле обобщенных функций могут использоваться вариантные операторы |
FUNCTION S|tr|ing_from_rect_or_point(
|
Список вариантов, задающих ветвь такого условного оператора, состоит из элементов вида N/ тип, где N - это порядковый номер варианта типа в списке вариантов, начиная с 1 (а тип - соответствующий тип первого вариантного параметра).
Так же, как и в случае перечислений, ветвь |
В отличие от обычного кода, при компиляции каждого варианта "обобщенной" функции, все ветви, не соответствующие текущей компилируемой сигнатуре, просто пропускаются. Поэтому декларации переменных в таких ветвях недоступны другим ветвям.
При использовании таких перегруженных функций, отыскиваются функции по именам и сигнатурам "обобщенных" параметров. |
VII. 12. Методы для индексации.[] - организация многомерных массивов |
В классе может быть декларирована единственный метод, вместо имени которого указывается точка, а
параметры заключены в квадратные скобки:.[] - метод. Обращение к такому методу выглядит для объекта
класса X почти как к массиву:
Кроме этих особенностей, если для такой функции декларируется "сеттер"-метод, то такая
функция может использоваться в левой части оператора присваивания:
|
С помощью методов индексации организуются многомерные массивы, например, как в классе |
--------------------------------
'access Items[] via .[i, j] method'
|
VII. 13. Операторы |
В главе о синтаксисе декларации функци й кратко описывался синтаксис декларации операторов. Здесь информация об операторах и их применении в коде собрана вместе. |
Оператор - это статическая функция, которая предназначена для использования в выражениях вместо
встроенных операций +, -, *, /. Ее декларация отличается от декларации обычной функции:
Например:
Кроме операторов с двумя операндами, может так же декларироваться оператор для операции '-' с
единственным операндом:
|
Как минимум, один из типов параметров должен отличаться от базовых типов |
Чтобы операторы могли использоваться в функции, она должна иметь модификатор |
Имена параметров для оператора в декларации отсутствуют (указывается только тип), но подразумевается,
что параметров два, и первый имеет имя |
Класс, содержащий операторы, должен содержать модификатор |
Пример кода оператора: |
OPERATOR {Matrix} * REAL ==> {Matrix}, NEW
|
VII. 14. Многопоточность |
Многопоточность в AL-IV реализуется классом Потоки исполнения всегда образуют иерархию: если поток A запускает поток B, то B становится
подчиненным по отношению к A. Если поток A завершается, то поток B может продолжать работу, но
коммуницировать с запустившим потоком он уже не сможет. Тем не менее, операция Сам объект потока, когда он запускается, на самом деле тоже исчезает из адресного пространства
запустившего потока как объект. Но на стороне запустившего потока формируется "фантомный"
объект Для реализации некоторого процесса, выполняющегося в отдельном потоке, следует унаследовать свой
класс от |
Иногда желательно получать дополнительно информацию о ходе выполнения задачи, переданной потоку.
Например, для индикации процентов исполнения. Помимо штатной возможности регулярно создавать на стороне
запущенного потока объекты, и передавать их контролирующему потоку ( |
VII. 15. Нативные (низкоуровневые) функции |
Нативные функции могут быть только статическими (не могут быть методами). Они должны иметь
модификатор
Есть два основных варианта нативных функций: содержащие только нативный код, и имеющие обычный код AL-IV, и завершающий нативный код (что позволяет подготовить часть параметров в локальных переменных, или проверить некоторые условия, и предотвратить выполнение нативного кода, если необходимо) .
В первом случае после двоеточия сразу располагается либо строковая константа-литерал (может быть
многострочной, с префиксным символом '@', который автоматически добавляет символы завершения
строки в константу после каждой строки).
В качестве константы может быть указана так же именованная строчная константа, но тогда ей должно
предшествовать ключевое слово |
Во втором случае, сначала идет код AL-IV:
В обеих реализациях приведенной выше функции Writeln_number, имеется проверка на неотрицательность параметра. T.e., оба приведенных примера эквивалентны. |
Содержимое строчной константы, указанной в качестве тела нативной функции, практически без изменений вставляется в код результирующей функции, и это должен быть код на целевом языке - том, в который выполняется компиляция проекта. Но могут быть особенности, в зависимости от языка. Например, для языка Паскаль первые строки, начинающиеся с 'var', рассматриваются как декларации локальных переменных, и вставляются до слова begin, начинающего результирующую нативную функцию. (На самом деле, если первая строка начинается с var, то в секцию декларации переменных до begin попадают все строки, до последней строки, начинающейся с var. В том числе, все промежуточные строки, не начинающиеся с var - это позволяет в секции декларации использовать, в том числе, директивы условной компиляции). Во всех случаях, для нативных функций, возвращающих результат, переменная |
Для доступа к своим параметрам и локальным переменным нативная функция в теле должна добавлять префикс 'X_' к их именам. Для работы с объектами и их полями и методами, надо точно знать во что превращается код после работы компилятора AL-IV - для конкретного целевого языка. Обычно, поля получают префикс 'F_', методы и функции 'M_'. Следует учитывать, что не все языки программирования учитывают регистр букв в именах, и в Паскале имена a и А тождественны. Можно ознакомиться с примерами написания нативного кода для C#, Pascal, Java - в библиотеке функций. |
Класс, содержащий нативные функции, должен иметь модификатор |
VIII. Зачем нужен еще один язык? |
VIII. 1. Настоящая многоплатформенность |
Да, существует возможность создавать приложения, которые действительно будут многоплатформенными. Для этого нужно выбрать язык (С++, С#, Java, Pascal) и использовать какой-нибудь фреймворк (библиотека классов). На этом пути вас ждет масса приключений и разочарований. Приключений - потому что авторы языков и библиотек, которые вы выбрали, очень часто имеют свое представление о том, что важно, что не нужно вам. Идут путями, о существовании которых вам раньше даже не приходилось задумываться. Будьте готовы к тому, что какую-нибудь простенькую проблемку вы будете решать неделями, перекапывая весь Интернет, роясь в тоннах чужих исходных кодов, и перечитывая сотни ( ладно, десятки) страниц различных форумов. Разочарований, потому что иногда придется пересматривать свои потребности, исходя из ограничений выбранного вами инструмента. Или прекращать использовать выбранную связку, и искать другую, переписывая на новый лад все ранее написанное. |
В чем же фундаментальное отличие AL-IV в плане многоплатформенности, если это всего лишь надстройка над одним из существующих языков (над С #, Delphi, Free Pascal или Java) ? Особенность AL-IV в том, что он изначально не ориентирован ни на какую платформу. Вы пишите код только один раз. Для запуска программы на другой платформе достаточно поправить конфигурационные файлы и вызвать компилятор. Требуется лишь обеспечить поддержку необходимой платформы. К счастью, платформ (операционных систем) не так много. Существует вероятность, что со временем, у нас будет поддержка всех основных платформ. На данный момент (июнь 2019) дерево поддерживаемых платформ выглядит примерно так: |
|
Что, если какая-либо из поддерживаемых ветвей отпадет (например, перестанет поддерживаться желаемая целевая платформа, или средство разработки неожиданно подорожает) ? На этот вопрос ответ есть. Он заключается в простоте языка AL-IV. Компилятор для него (компилирующий в промежуточный целевой язык) изготавливается за сравнительно короткое время. Всегда можно вернуться к генерации кода на языках C++/Java/Python/... или сделать новый генератор. Задача построения набора переходных нативных классов, реализующих функциональность базовых библиотек, может оказаться сложнее (но и этот вопрос решаем), т.к. базовая библиотека изначально невелика и спроектирована так, чтобы по возможности упростить такую работу. |
VIII. 2. Надежность |
Практически все современные языки программирования выросли из древних примитивных "ассемблеров", допускающих небезопасные операции, адресную арифметику. Нет на данный момент языков высокого уровня, в которых было бы невозможно обратиться к несуществующему объекту, получить во время работы исключение в результате ошибочного доступа по нулевому адресу, а в некоторых тяжелых случаях напороться и на порчу произвольной памяти. Вы можете использовать т.н. "управляемую" (managed) память в С++ (в С # почти все объекты хранятся в такой памяти), или использовать none- объекты в objective-c. Но часть кода все равно будет написана в старом небезопасном стиле, и изменить эту часть вам, скорее всего, не удастся (даже если это ваш собственный код). Даже в случае современных С #/ Java вы не будете избавлены от необходимости обеспечивать в своем коде проверки на равенство указателя значению null или предусматривать обработку исключений. |
В случае AL-IV ситуация отличается кардинально. На уровне компилятора (и самого языка) контролируется выход за пределы массивов (возвращая фиктивный NONE элемент или предотвращая операцию записи), обращение к неприсвоенным объектам, гарантируется инициализация всех переменных, предотвращается зацикливание и бесконечная рекурсия. Имеются встроенные средства тестирования кода, с контролем степени "покрытия" кода тестами. Программирование с AL-IV становится спокойным и монотонным занятием, без экстрима и авантюризма. |
Исключения в коде AL-IV невозможны. При разработке нативных методов/ функций рекомендуется следовать этой парадигме, обеспечивая в случае отказа в финальном коде безболезненную обработку ошибок в стиле пост-обработки списка ранее произошедших ошибок, и только с целью выяснить, успешно ли была выполнена последняя группа операций. В нормальных ситуациях достаточно сообщить о возникших проблемах (вывести их в лог, отобразить на экране и т.п.) |
V III. 3. Зачем нужен новый синтаксис? |
В действительности, всегда существует возможность остаться в рамках существующего синтаксиса, но при этом изменить семантику. |
При разработке нового синтаксиса основной целью было упростить работу с исходным кодом в произвольном текстовом редакторе (с поддержкой UTF-8 - это единственное требование к такому текстовому редактору) . |
Именно отсюда - требование на запись ключевых слов только В ВЕРХНЕМ РЕГИСТРЕ. В этом случае исходный код проще читать (и ненамного сложнее редактировать). |
Что касается отсутствия начальной скобки блочного оператора, и специального символа завершения каждого оператора. Их отсутствие делает текст чище, и упрощает модификацию текста (такие операции, как рефакторинг). И при этом, не затрудняет чтение. А для целей перевода ключевых слов на национальные языки - еще и сокращает количество слов, требующих перевода. Как минимум, исключает слово END - КОНЕЦ из словаря. |
Об ограничениях на количество вложенных операторов, на количество операторов между блочными комментариями. Эти ограничения мало влияют на возможности программиста. Слишком много уровней вложенности существенно затрудняют понимание кода. При использовании нескольких отступов, когда уровень вложенности становится слишком глубок, ширина строки оказывается слишком узкой для текста, и строки кода все чаще приходится делить на части. Поэтому, вынесение глубоко вложенных блоков в отдельные методы/функции - весьма корректное требование. Разместить блочный оператор для разбиения слишком длинной последовательности операторов - вообще не является чрезвычайно сложным пожеланием. |
Остается вопрос только насчет ограничения на три параметра на функцию/метод. Первоначально, при вводе такого ограничения, предполагалось, что если оно окажется слишком сложным для постоянного следования, то будет снято или ослаблено. Но в процессе разработке довольно сложного и объемного программного кода (компилятора языка, редактора исходного кода, и других приложений) выяснилось, что данное требование более чем легко исполнимо, и не должно представлять трудностей. При этом вполне очевидно, что ограничение на максимальное число параметров существенно упрощает работу с библиотеками классов/функций, так как разработчику не приходится запоминать большие списки параметров. Ограничение было снято в итоге, и заменено на требование явно указывать имя параметра в форме присваивания, начиная, как минимум, с четвертого параметра. Но это только для того, чтобы еще более упростить возможный рефакторинг кода путем вынесения кода из вложенных блоков в отдельные функции, или для адаптации существующего кода, ранее написанного на других языках программирования. |
VIII. 4. Где цикл "while" ? |
Циклы вида while/ repeat... until небезопасны, так как могут приводить к зацикливанию программного кода без какого-то шанса завершить этот цикл. Циклы типа FOR i IN [...] безопасны в этом плане, т.к. рано или поздно завершаются (возможно, очень много придется ждать, но не вечность). |
При программировании в Алфор следует для каждого цикла, для которого в другом языке был бы использован
while, использовать оператор FOR, задавая в качестве диапазона, например, [0 TO N], где N - верхнее
допустимое число итераций. И первым оператором внутри цикла ставить выход по анти-условию продолжения цикла:
|
Такой подход гарантирует прекращение цикла хотя бы по условию исчерпания заданного диапазона. |
VIII. 5. Зачем нужен новый способ управления памятью? |
С тех пор, как была изобретена куча динамических данных, на самом деле, в плане управления памятью было сделано только одно нововведение: автоматическое уничтожение объектов при достижении счетчиком использования значения 0. Правда, при этом выяснилось, что могут образоваться взаимные ссылки объектов друг на друга (а в более сложных случаях - кольцевые замкнутые маршруты взаимного использования), в результате чего автоматически удалить объект не получается. Для устранения возникшей проблемы была придумана т.н. "чистка мусора". К сожалению, данная процедура переводит абсолютно все системы, использующие эту методику для освобождения циклически связанных объектов, в разряд медленных и непредсказуемых. А это значит, что их становится нельзя использовать в системах реального времени. Или даже нежелательно использовать в системах массового обслуживания. |
Да, всегда есть возможность для критичных подсистем отказаться от управляемой памяти, и вести разработку в "старом стиле", напрямую управляя выделением памяти. Но при этом исчезают преимущества автоматического освобождения памяти. И это, на самом деле сложный путь, так как давно уже программы не пишутся с нуля. Программисты постоянно используют уже существующие библиотеки функций, классов. Если нет возможности использовать управляемую память, то нет и возможности использовать классы/функции, использующие управляемую память. Возможности программиста резко сокращаются, разработка замедляется. |
Совсем другое дело, если у вас есть возможность работать с автоматически освобождаемыми объектами, но при этом нет необходимости отказываться от разработки приложений реального времени. Чистка мусора не нужна, объекты освобождаются немедленно в тот момент, когда это требуется - это ли не мечта программиста? |
Конечно, в случае нового способа приходится несколько менять стратегию создания объектов. Как минимум, приходится думать о времени жизни объекта в точке программного кода, где он создается. И, конечно же, появляется необходимость держать массивы указателей на дочерние объекты. Но это небольшая потеря по сравнению с приобретением возможности полностью отказаться от чистки мусора (и от самого мусора в динамической куче). |
VIII. 6. Зачем встроенная поддержка операторов SQL? |
Действительно, как сочетается стремление сделать язык максимально простым и встраивание прямой поддержки SQL- выражений? Ответ: такая поддержка позволяет проверять значительную часть семантики SQL- запросов на этапе компиляции программы. А именно: соответствия имен полей действительным именам полей ( объявленным в декларации таблиц TABLE), корректность их использования (учет того, что поле может быть null, или является автоинкрементным и, соответственно, ему нельзя присвоить значение в утверждении UPDATE, например). И проконтролировать собственно синтаксис SQL -запросов. Эти проверки выполняются на этапе компиляции, позволяя уменьшить вероятность того, что программа, предназначенная для работы с БД, будет запущена с явными ошибками в своем коде. |
Этот принцип - возможность статического анализа корректности операций на этапе компиляции - значительно упрощает разработку. К сожалению, в отношении SQL в настоящее время этот принцип обычно не действует, хотя работа с БД является одной из ключевых в современной практике программирования. В AL-IV сделана попытка исправить эту тенденцию. |
В отличие от обобщенного программирования, встраивание некоторых специализированных возможностей в язык, например, операторов SQL, или комплексных чисел, практически не увеличивает порог вхождения. При написании кода, вы не используете эти возможности, и можете даже не знать об их существовании. При чтении чужого кода, придется ознакомиться с новой для вас возможностью, если ее использование встретилось в этом коде. Но ознакомиться со специализированным расширением языка на порядок проще, нежели:
|
VIII. 7. Почему нет возможности управлять разрядностью переменных? |
Потому что это делает ваш код проще (и уменьшает число возможных ошибок при одновременном использовании якобы однотипных значений с различной разрядностью). Во многих современных языках имеется возможность двойственного определения типов переменных: для значений, для которых разрядность не очень важна, используется базовый тип (например, Integer), а в случаях, когда его явно недостаточно, или наоборот, требуется экономия разрядности, применяются типы с уточнением разрядности (Int64, Smallint, Shortint). |
В итоге, образуется несметное количество различных типов данных и их сочетаний. В результате в процессе разработки, приходится предусматривать ситуации, когда разрядности одной переменной может не хватать для хранения результата, полученного в результате операций с переменными с другой разрядностью. (На самом деле, никто ничего не предусматривает, и вместо этого, есть возможность просто получить неправильные результаты, без какого-либо разумного объяснения, что же, собственно, произошло, и без возможности что-либо исправить в коде). Зачем все эти тонкие спецификации разрядности нужны, если используются в действительности только для экономии памяти? Проще отказаться от них навсегда, существенно упростив для программиста выработку решений о том, какие типы данных использовать. |
По этой причине в AL-IV нет беззнаковых типов данных (кстати, их нет, например, и в Java). И нельзя задавать разрядность каждой переменной отдельно. Только для всех целочисленных или вещественных переменных сразу, задавая опции компилятора (/int32, /$REAL=EXTENDED/DOUBLE/SINGLE). |
VIII. 8. Где тип данных CHAR? |
Этот тип данных устарел, и не отражает современных реалий. В случае использования кодировки utf-8, один символ может кодироваться последовательностью байтов, от одного до шести. Т.е., по сути, для хранения одного символа, нужна строка. Что и сделано в AL-IV. |
В AL-IV каждый символ строки, в свою очередь, является строкой. Таким образом, извлекая его операцией S[n], мы фактически вызываем функцию S.Substring(n, 1). |
VIII. 9. Почему нет указателей на структуры? |
Потому что структуры введены в язык прежде всего как средство иерархического управления наборами данных. Они позволяют агрегировать данные (поля), и при этом гарантируют, что структуры всегда хранится только в одном экземпляре, и при выходе из области видимости гарантированно освобождает память. |
Структуры - это промежуточный тип данных между простыми типами и классами. С одной стороны, они содержат отдельные поля (и передаются в функции фактически по ссылке), с другой - они присваиваются практически как простые переменные (путем простого копирования), и не могут модифицироваться в функциях, если являются параметрами (т.е. всегда передаются только для чтения, в нотации C++/Java/Pascal языков - как константные параметры - const). |
В AL-IV отсутствует возможность работать с указателями на структуры или на их части. |
Отсутствие указателей и адресной арифметики существенно повышают надежность кода. Индексирование элементов массива значительно безопаснее, т.к. у компилятора в этом случае есть информация о том, к какому объекту (массиву) производится доступ в коде, и он может обеспечить контроль выхода за его границы, хотя бы динамический (во время выполнения). |
VIII. 10. Краткость кода |
a. Краткие именаПри написании кода на AL-IV, вы можете использовать краткие имена переменных, и код становится кратким. Как на заре программирования, когда программисты часто использовали сокращенные имена переменных, ограничиваясь одной-двумя-тремя буквами, и вообще не заботились о том, чтобы в будущем самим понять, что они там по-быстрому накалякали. С той разницей, что компилятор потребует предоставить при декларации переменной/функции/типа данных и более длинный вариант имени (не менее 8 символов в сумме), и при желании понять, для чего предназначена переменная, всегда можно найти ее декларацию. В случае использования специализированного IDE, достаточно кликнуть по имени переменной, чтобы ее декларация была продублирована в окне подсказки по текущему символу. |
b. Префиксный вызов функцийВы можете существенно уменьшить количество вложенных скобок в выражениях,
заменяя классический вызов функции с параметром в скобках на префиксную форму. Например:
Сравните:
В первом случае (префиксный вариант) код и короче, и намного понятней (второй вариант синтаксически так же верен для AL-IV, впрочем). |
c. Удаление избыточных проверокЕсли вы пишете на AL-IV, вам не требуется постоянно проверять на null (в случае AL-IV - на NONE, но в любом случае - не требуется). Компилятор сам выполнит необходимые проверки, и в случае, если объект является NONE, то обращение к его полям/методам не приведет к исключению/падению приложения/синему экрану смерти. Что произойдет? Чаще всего, ничего не произойдет. Будет возвращено значение NONE для методов/функций, возвращающих объект, и для объектов-полей. А для чисел/строк/перечислений будет возвращен 0. Таким образом, проверка на NULL (в нашем случае - NONE) часто оказывается избыточной, т.к. поля
NONE-объекта существуют физически, но содержат NONE-значения. Следовательно, вместо проверки
Вам так же не требуется заботиться о делении на ноль, или вычислении операций с операндом NaN. Будет возвращено значение NaN. Падение приложения в этом случае не предусматривается. Если полученное значение вас не устраивает, вы можете найти причину неудачи, и исправить ее. Возможно, речь идет о том самом делении на ноль, или об обращении к математической функции с недопустимыми параметрами. Но это точно не причина падать для всего приложения. |
d. Операторы LIKEВам не требуется постоянно выполнять рефакторинг при написании кода, только для того, чтобы повторно
использовать уже написанный выше кусок кода. То есть, да, его можно оформить как отдельно стоящую функцию,
придумать для нее имя, оформить заголовок, придумать, как передавать ей параметры, и все это - чтобы
один-два раза использовать повторно. А можно просто ограничить повторно используемый код
"скобками"
--------------- ' не хочется переписывать ', REUSED
и далее в коде обратиться к этому фрагменту:
LIKE.......... ' не хочется переписывать '
Это как бы макрос (что было бы очень плохо - см. на C/C++ с их макросами), но без возможности вложенного вызова других операторов LIKE, или выхода за пределы текущего класса. |
e. Оформление блочных операторовВ языке AL-IV нет скобок begin/end или {...}. Вам не придется тратить пару лишних строк кода на это оформление вложенных блоков (у вас появится время на то, чтобы придумать, как уложиться в допустимые три уровня вложенности операторов FOR/CASE). Код становится практически таким же кратким, как в Python (но в случае, если у вас собьются ведущие пробелы/табуляции, код не будет испорчен - вложенность блоков определяется завершающим блоки символом ';' . При переносе на новую строку не используются специальные символы, засоряющие текст - достаточно соблюсти пару простых правил ( завершить предыдущую строку запятой, открывающей скобкой '(', '[', или начать строку продолжения с последовательности символов, которые не могут начинать новый оператор. Например, начать с кавычки или знака операции '+', '-', '&&' и т.п.). |
f. Декларация локальных переменныхВ AL-IV локальная переменная декларируется в том месте, где она впервые нужна (например, получает первое
значение). И (это важно, и это действительно отличается от большинства других языков) действует до
конца функции. Фактически, это означает, что локальные переменные были объявлены как бы в самом начале
функции, и проинициализированы значением по умолчанию (нулем, пустой строкой, объектом Это может выглядеть странно по сравнению с большинством других языков программирования. Но в реальности,
не имеет (почти) никаких недостатков, и позволяет дополнительно сократить код. Например:
(Недостаток, на самом деле, есть: если вы декларируете первый раз накопительную переменную/массив и т.п. - во вложенном цикле, и не очищается ее до повторного входа в этот цикл, то накопление продолжится - но этот косяк будет полностью на вас, извините, хотя и сломает только ваш алгоритм, но не станет ронять всю программу). |
g. Автоматическое освобождение объектных переменныхДа, для большинства современных языков это давно не новость. Но есть отличия: программе на языке AL-IV не требуется сборщик мусора. Это, как минимум, позволяет компилировать код для языков/систем, в которых нет автоматического освобождения объектов при обнулении счетчика использования (например, Delphi 32/ Free Pascal). И при этом сохранять свойство автоматического освобождения ресурсов при исчерпании ссылок на них. Для краткости кода это означает отсутствие дополнительного кода, занимающегося высвобождением переменной по окончании ее использования. (Причем, если в том же C# рекомендуется вызывать Dispose для тех же битмапов или MemoryStream, то для AL-IV этот Dispose вызывается автоматически, при завершении существования соответствующих экземпляров этих классов). |
Содержание |
В начало
|