$$OUT=-

$$START!

III. Классы и объекты

III. Classes and objects

III. 1. Классы

III. 1. Classes

III. 1. a. Декларация класса

III. 1. a. Class declaration

 

Синтаксис.

 

/*
CLASS
{имена} , модификаторы  :
    IMPORT: {Class1} ... ;

    BASE CLASS {базовый_класс}
    поле1
    поле2
    ...
    метод1
    метод2
    ...
    --------------- 'метка секции1'
    ...
    --------------- '
метка секции2'
    ...
END
*/

 

В одном файле располагается декларация одного класса.

Все прочие декларации (перечислимые типы, функции, константы, поля) существуют только в пределах классах.

Глобальных (статических) полей классов не бывает, все поля являются членами каких-либо экземпляров классов.

 

 

Syntax.

 

/*
CLASS
{names}, modifiers :
    IMPORT: {Class1} ... ;

    BASE CLASS {Base_class}
    field1
    field2
    ...
    method1
    method2
    ...
    --------------- 'section label1'
    ...
    --------------- 'section label2'

    ...
END
*/

 

One file contains exactly one class definition.

All other declarations (enumerations, functions, constants, fields) are located only  in classes and belong them.

The are no global (static) class fields, all the fields are members of certain objects.

 

  • Код AL-IV всегда располагается между строками с символами конца и начала многострочного комментария /* и */.
  • Имена классов заключаются в фигурные скобки.
  • Имя класса начинается с прописной буквы.
  • Имя класса может разделяться на две части символом '|'. До этого символа находится краткое имя класса, после - длинное имя класса.
    Например: {My|_class} определяет два имени - краткое {My} и длинное {My_class} для одного класса.
  • Длинное имя должно быть не менее 8 символов (не считая фигурные скобки).
  • Имя файла класса (без расширения класса) должно совпадать с длинным именем класса (без фигурных скобок). Но нарушение этого правила не вызывает ошибку, только предупреждение.

 

Основная часть декларации класса - это определения полей и функций.

  • Поля декларируются в форме
    {тип} имена = значение, модификатор
  • Тип - это один из системных простых типов BOOL, BYTE, INT, REAL, STR, либо имя класса в фигурных скобках (начинается с прописной буквы), либо имя перечисления или записи в фигурных скобках (начинается со строчной буквы).
  • Если имена поля или метода начинаются с прописной буквы, то имя - публичное.
  • Со строчной буквы начинается имя скрытого поля или метода. Они доступны в самом классе, и в наследниках класса.
  • Декларации в классе могут разбиваться на секции с помощью оператора-разделителя:
    ----------- 'метка разделителя'
  • Внутри одной секции не должно быть более 7 полей.
  • Декларация функции так же завершает текущую группу.
  • Если правило "не более 7 полей в группе" не выполняется, модуль должен иметь модификатор BAD.

 

 

  • The AL-IV code is always located between lines containing symbols of the end and the start of multi-line comments: /* and */.
  • Class names are enclosed into figure brackets.
  • Class names always start from an uppercase letter.
  • Class name can be separated onto two parts by the symbol '|'. Before the symbol a short name of the class is defined, after the '|' symbol - the rest of a long name of the class.
    E.g.: {My|_class} defines short name {My} and full name {My_class} for the same class.
  • A long name must not be shorter then 8 characters.
  • Class file name (w/o extension) should much the long class name (w/o figure brackets). But violating this rule leads only to a warning, not to an error.

 

The main part of a class declaration consists of declarations of fields and methods.

  • Fields of a class are declared in form
    {type} names = value, modifier
  • Type - is one of system simple types BOOL, BYTE, INT, REAL, STR or a class name in figure brackets (its name is starting from an uppercase letter) or a enumeration or a record name in figure brackets (name is starting from a lowercase letter).
  • If field and method names are starting from an uppercase letter, then the name is Public.
  • If the first letter of a name is in lowercase then the name is hidden. Such methods and fields are accessible only in the module where the class is declared, and in inherited classes.
  • Groups of declarations in a class can be separated onto sections with a separator in form:
    ----------- 'separator label'
    (at least two '-' signs)
  • Each section should not contain more then 7 fields.
  • Function declaration also ends a group of declarations.
  • If the rule "maximum 7 fields in a section" is not satisfied, then such class must be marked with a modifier BAD.

 

 

III. 1. b. Наследование, модификаторы

III. 1. b. Inheritance, modifiers

 

Для указания предка класса, первым в классе после оператора IMPORT записывается:
BASE CLASS {Base_class}

  • Если конструкция BASE CLASS ... отсутствует, то класс не имеет предков, кроме общего для всех классов предка - безымянного класса {}.
  • Если в классе переопределяются методы предка, то все такие переопределения начинаются словом OVERRIDE:
    OVERRIDE some_name(paramer) ==> result_type:
                    ...
    .
  • Для выполнения действий при создании каждого экземпляра класса, после присваивания значений полей, используется процедура CONSTRUCT|ION
    CONSTRUCT :
                    ...
    .
  • Для выполнения действий при уничтожении объекта, используется специальная процедура
    DESTRUCT :
                   ...
    .
  • Если классы использует деструктор, то он обязан иметь модификатор DESTRUCTORS в заголовке.

 

 

To specify an ancestor for a class its declaration is written in a form (immediately after IMPORT):
BASE CLASS <Base class name 1>

  • If a construction BASE CLASS ... is absent, then the class has no other ancestors except the common for all classes unnamed class {}.
  • If the are methods in a class which are overriding correspondent methods of a base class then all those methods are declared starting from a keyword OVERRIDE:
    OVERRIDE some_name(paramer) ==> result_type:
                    ...
    .
  • To assign other initial values to fields of a base class and to do something else on a create time of an instance of a class, a procedure is used
    CONSTRUCT :
                    ...
    .
  • To do something special when an object is destroyed, a procedure is used
    DESTRUCT :
                   ...
    .
  • If a destruction procedure is used in a class it is necessary to add a modifier DESTRUCTORS to the header of the class.

 

 

При переопределении метода в классе:

  • Используется префикс OVERRIDE вместо METHOD.
  • Указывается только одно имя метода.
  • Перечисляются (в скобках, через запятую) все определения параметров переопределяемой функции (должны совпадать первые буквы имен соответствующих параметров). Типы должны быть совместимы, размерности для массивов - совпадать.
  • Для методов, возвращающих значение:
    • указывается тип возвращаемого результата.
    • Пример:
      OVERRIDE FUN enabled ==> BOOL :
            RESULT = o.Edit1.Text != "" .

 

Переопределённый метод может вызывать базовый метод (одноимённый метод родительского класса).

  • Для явного вызова базового метода в теле переопределённого метода используется запись BASE.
  • При этом все параметры передаются обычным способом, в том числе явно передаётся сам объект как неявный параметр:
    BASE(параметры).
  • Метод, не возвращающий значение, либо должен хотя бы раз вызвать базовый метод (обычно, вначале), либо ему следует добавить модификатор REPLACE.

 

 

When a method is redefined in a class:

  • A prefix OVERRIDE is used instead of the METHOD.
  • Only one name of the method is specified.
  • All the parameters of a base method are listed (in parenthesis, comma separated). First letters of correspondent parameter names must much. Types must be compatible by types and by dimensions (for arrays).
  • For methods returning a value:
    • data type of a returning value is specified.
    • An example:
      OVERRIDE FUN enabled ==> BOOL :
            RESULT = o.Edit1.Text != "" .
       

A redefined method can call a base method (the same named method of the base class).

  • To call explicitly a base method in a body of a redefined method a syntax is used: BASE.
  • All the parameters are passing by a usual way, and the object itself is passed implicitly as usual : Base(parameters).
  • A method not returning a value, should at least once call a base method (usually, at the start), else it is necessary to add a modifier REPLACE to the overriding method.

 

 

Модификаторы для класса записываются после имен класса , через запятые. Имеются модификаторы:

  • ABSTRACT - класс предназначен только для наследования новых классов на его основе, создавать объекты этого класса нельзя.
  • BAD - класс не выдерживает требований по оформлению кода (не более 3 параметров, не более 3 уровней вложенности блочных операторов, не более 7 полей в секции класса, не более 7 простых + 7 блочных операторов в секции кода).
  • BITWISE - в классе используется поразрядная логика.
  • BYTES - в классе используются байты.
  • DESTRUCTORS - имеется деструктор.
  • NATIVE - имеются "нативные" функции.
  • RECURSIVE - имеются рекурсивные фукции.
  • SHORT_STRINGS - используются короткие строки.
  • STOPPING - используется оператор STOP.
  • UNTESTED - есть не оттестированный код.
  • SAFE - всё хорошо, класс оттестирован, не содержит никаких замечаний по безопасности или оформлению.
  • DEPRECATED('text') - класс поддерживается, но его использование осуждается. В скобках и апострофах указано, что использовать в качестве альтернативы. Желательно как можно быстрее отказаться от использования этого класса, т.к. в скором времени он может более не поддерживаться.
  • ABANDONED('text') - использование этой версии класса запрещено. В скобках и кавычках указано, что использовать в качестве альтернативы (не обязательно это класс, возможно, технический приём, или поле другого класса). Попытка объявить переменную с таким классом или функцию, возвращающую объект такого класса (и любая другая ссылка на класс) вызывает ошибку компиляции.

 

A modifier for a class is written following the class names. Such as:

  • ABSTRACT - the class is intended only for deriving new classes on base of this class, it is not allowed to create objects of the class itself.
  • BAD - the class is not satisfying requirements on code style (not more then 3 parameters for a function, not more then 3 nesting levels of block statements, not more then 7 fields in a section of a class, not more then 7 simple statement + 7 block statements in a section of a block in a function code).
  • BITWISE - bitwise logical operations between integer values are used.
  • BYTES - bytes are used in the class.
  • DESTRUCTORS - the class has a destructor.
  • NATIVE - there are native functions in the class.
  • RECURSIVE - there are recursive functions in the class.
  • SHORT_STRINGS - strings with a modifier MAXLEN[n] are used in the class.
  • STOPPING - a STOP operation is used in the class.
  • UNTESTED - there is an untested code in the class.
  • SAFE - all is OK, class is tested fully and there are no warnings on a safety or style.
  • DEPRECATED('text') - the class is still supported but its using is deprecated. The text in apostrophes contains information about an alternative which should be used as soon as possible still in future the class can become not supported.
  • ABANDONED('text') - the class is abandoned. Any reference to it leads to a compilation error. The text contains information about an alternative.

 

 

III. 1. c. Объекты. Сильные и слабые ссылки

III. 1. c. Objects. Strong and weak references

 

Переменная класса (экземпляр класса) является объектом класса.

  • Объекты класса декларируются как переменные с именем класса в качестве типа данных.
    Например:
    {My_class} M|y_object = {My_class}
  • Поле или переменная, не имеющая в именах завершающего символа подчеркивания, является удерживающей ссылкой объекта.
  • Переменные_ с завершающим подчеркиванием в имени являются слабыми ссылками и лишь ссылаются на существующие объекты.
  • Слабая ссылка действительна лишь до тех пор, пока они объект существует (на него ссылаются переменные-сильные указатели, или жив владелец объекта).
  • Все локальные переменные функций являются сильными ссылками. Слабыми ссылками могут быть только поля класса.
  • При обнулении счетчика использования сильными ссылками объект уничтожается. Все использующие переменные немедленно начинают ссылаться на NONE.
  • Если в момент создания объекта для него явно указан владелец (OWNED BY), то наличие сильных ссылок на него уже никак не влияет на время жизни объекта: он будет уничтожен вместе со своим владельцем, при этом все ссылки на него, сильные или слабые, перенаправляются на NONE-объект.
  • NONE - объект - это специальный объект класса, имеющий все поля равными NONE (и 0 - для чисел, пустым строкам - для строк, и т.д.). Запись в поля этого псевдо-объекта игнорируется, чтение из его полей возвращает NONE-значения, вызов методов не выполняет никаких действий.
  • Все объектные переменные (как сильные, так и слабые ссылки) изначально имеют значение NONE, чтение за пределами массива объектов так же возвращает NONE.

 

 

A variable of a class type (a class instance) is an object of the class.

  • Objects are declared by specifying a correspondent class name in figure brackets as a type name of the variable.
    E.g.:
    {My Class} M|y_object = {My_class}
  • A field or a variable not having trailing underscore characters in its names, is a keeping reference to an object.
  • If an object_ name has a trailing underscore character, it is defined not to own an object but to be just a weak reference to to another object.
  • Such weak object reference variable links to it just while it exist and there are object variables referencing such object strongly (or an owner of the object still exists).
  • All the local variables in a function are strong references always.
  • When a count of strongly referencing variables becomes zero, the object is destroyed and all the weak pointers start pointing to NONE value immediately.
  • If at create time for an object an owner was specified explicitly (OWNED BY), then presence of strong references to it has no effect: it will be destroyed together with its owner, and at that moment all the references to it, either strong or weak will be redirected to the NONE object.
  • NONE - is a special object of a class, having all the object fields equal to NONE (and 0 for numbers, "" - for strings, etc.). Writing to fields of such pseudo-object is always ignored, reading is always returning NONE and 0 values, calling its methods does not lead no any valuable operations.
  • All the object variables initially are set to NONE, and if an object is read out of bounds of an array, also NONE is returned.

 

ПРАВИЛО
  • Поле FA класса A, являющееся удерживающей ссылкой на объект, не может иметь тип класса B, являющегося предком по отношению к классу A.
  • Если класс А имеет удерживающее поле класса B, то класс B не может иметь удерживающих полей класса А
    или классов, родственных A по прямой линии (как предков, так и потомков).
  • Если класс А1 содержит удерживающее поле класса А2, класс А2 содержит удерживающее поле класса А3, и т.д., и класс А(n-1) содержит удерживающее поле класса А(n), то класс А(n) не может содержать удерживающих полей классов А1, А2, ..., А(n-1).
  • В частности, объект не может ссылаться на объекты своего класса.
  • В результате, невозможно создание цепочек взаимного владения.
  • Одноранговые сети, графы, и т.п. организуются с помощью слабых_ ссылок.

 

THE RULE
  • A field FA of a class A which is a strong reference to an object can not belong to a class B which is a direct ancestor of the class A.
  • If a class A has an object field of class B which is a strong reference, then the class B can not have object fields which are strong references to class A
    or other classes which are direct ancestors or inheritances of A.
  • When a class A1 references strongly an object of a class A2, and the class A2 references strongly an object of a class A3 and so on, and a class A(n-1) references strongly an object of a class A(n), then the class A(n) can not contain object fields which are strong references to any of previous classes A1, A2, ..., A(n-1).
  • It is not possible to refer with a strong reference to an object of the same class, in part.
  • As a result, it is not possible to create circled chains of strong references of objects to each others.
  • Different kinds of peer networks of objects, graphs, lists etc. can be easy formed using weak_ only pointers.

 

Вновь созданные объект должен быть
    либо присвоен внешней (по отношению к функции) объектной переменной без подчёркивания на конце имени (сильной ссылке),
    либо добавлен во внешний массив сильных ссылок (операция , >> массив[]),
   
либо через запятую должен быть указан объект-владелец вновь созданного объекта, например, OWNED BY var_ref,
   
либо присвоен переменной, в имени которой присутствует строка temp (в любом регистре, например, Example|_TempVar).
  • Переменная является внешней по отношению к функции, если она:
    • либо является полем самого класса,
    • либо является полем внешней переменной,
    • либо является псевдо-переменной RESULT,
    • либо является полем переменной RESULT,
    • либо является полем объектного параметра.
  • Если вновь созданный объект хотя бы раз в теле функции присваивается переменной RESULT, то функция должны быть помечена маркером NEW.
  • Функция с маркером NEW может вызываться только в отдельном операторе присваивания, как и для оператора создания нового объекта. При этом вновь созданный такой функцией объект так же должен быть присвоен внешней сильной ссылке или temp-переменной.
  • Для результата NEW-функции не может быть применена конструкция OWNED BY, в отличие от прямого создания объекта.
Just created object should be either
    assigned to an external (for a function) object variable without an underscore at the end of its name (i.e. a strong reference to it should be created),
    or it should be added to an external array of strong references (an operation , >> array[]),
    or an owner object should be specified (an operation , OWNED BY var_ref),
    or it should be assigned to a (local) variable which has substring 'temp' in its name (in any case, e.g., Example|_TempVar).
  • A variable is an external to a function if it is:
    • either is a field of the class itself,
    • or it is a field of an external variable,
    • or it is a pseudo-variable RESULT,
    • or it is a field of the RESULT,
    • or it is a field of an object parameter.
  • If a newly created object at least once in a function body is assigned to the RESULT variable, then the function should be marked as NEW.
  • Function marked as NEW can be called only in a standalone statement like a statement where a new object is created directly. And the new object created with a function marked as NEW, also must be assigned to an external variable, added to an external array or assigned to a temporary variable.
  • For a NEW function result it is not allowed to use OWNED BY instruction.

 

III. 1. d. Методы

III. 1. d. Methods (events)

 

Все функции класса являются виртуальными.

  • Имеет место полиморфизм: вызов метода приведёт к вызову метода, определённого для экземпляра класса или наследника класса, представляющего объект.
 

All the class functions are virtual.

  • The is a polymorphism there: calling a method leads to call a method assigned for a certain class instance, representing an object.

 

 

III. 2. Работа с объектами классов

III. 2. Working with objects of classes

III. 2. a. Оператор создания экземпляра

III. 2. a. Creating an object instance

 

Конструкция объекта:

variable = {Class_name}(
    Field1 = expression, Field2[] << expression, ...)

  • Если значение присваивается переменной в операторе декларации этой переменной (который начинается с указания типа переменной в угловых скобках), и оператором создаётся объект именно этого типа, то в декларации может быть опущено имя типа декларируемой переменной:
    stream|_read_temp = {File_stream}(
           Path = source_path, Mode = 'READ')
  • Если при создании объекта не требуется инициализировать поля, то круглые скобки опускаются.
  • Если за именем типа и списком инициализации следует через запятую запись OWNED BY выражение, то тем самым созданному объекту назначается исключительный владелец.
    • Для такого объекта, счётчики использования строгими указателями не влияют на время жизни объекта: он существует, пока жив его владелец.
    • Если на момент создания объекта значение выражения в части OWNED BY равно NONE, то владелец не назначается, и при отсутствии других строгих ссылок на него, проживёт не долее, чем выполняется функция, в которой он создан.
  • Либо далее может располагаться операция добавления созданного объекта в один или несколько массивов объектов: >> переменная[].
  • Создаваемый объект должен быть присвоен либо внешнему для функции объекту (параметру или его полю, полю класса или его полю), или добавлен во внешний по отношению к функции массив строгих ссылок на объекты, либо ему должен быть назначен исключительный владелец (, OWNED BY). В противном случае, переменная, которой присваивается созданный объект, должен иметь в своём имени подстроку 'temp'.
 

Object construction:

variable = {Class_name}(
    Field1 = expression, Field2[] << expression, ...)

  • If a value is assigned to a variable in a declaration statement and actually the same type object is created as the variable declared, then type name of the declared variable can be omitted:
    stream|_read_temp = {File_stream}(
           Path = source_path, Mode = 'READ')
  • If fields initializations are not necessary, parentheses are omitted.
  • If an operation OWNED BY expression is followed (comma separated), this assigns an owner for the object created.
    • For such object, its strong usage counter does not affect its life time: it exists until its owner is destroyed.
    • If at the creation time the object assigned as an owner is referencing NONE, then the object owner is not assigned and it is most possible that the object created will be destroyed on a function end.
  • Either an operation of adding the object created to an array of strong references may follow (comma separated):
    , >> variable[]
  • An object created should be either assigned to an external (for a function) object field or variable,
    or it should be added to an external array of strong references using postfix operation: , >> array[]
    or an owner should be assigned to an object using postfix operation: , OWNED BY value.

    In other cases a variable on the left side of an assignment should have a substring 'temp' in its name.

 

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

 

A direct creating of an object become impossible if a field is present in an object, which is mandatory to initialize (has a modifier INIT|IALIZE), but it is not accessible (hidden for other modules) or made read-only using a READ modifier. In such cases the only way to create such objects is using a special construction function.

 

III. 3. Операторы уровня класса

III. 3. Class level operators

 

Первым в классе после заголовка должен быть указан оператор IMPORT, если он требуется. В операторе импорта перечисляются используемые классы (в том числе родительский класс, если класс образован не от базового класса {Object}).

IMPORT : {Класс1}, {Класс2}, ... ;

(В качестве завершения блока IMPORT может быть точка или точка с запятой).

 

The first in a class (following the class header) should be specified a statement IMPORT if it is required. In an import statement classes are listed which are used (including an ancestor class if the class is not descending from the common class {Object}).
IMPORT : {Class1}, {Class2}, ... ;
(the semicolon or the dot can be used to end the IMPORT statement).

 

Если класс имеет предка в иерархии, он должен быть указан оператором BASE CLASS {Имя}, но после оператора импорта, в котором указывается класс предка. Допускается форма с инициализацией полей: BASE CLASS {Имя}(Поле1 = Значение1, ... )

Для завершения оператора BASE CLASS не используется специальный символ.

 

If the class has an ancestor in its hierarchy, this should be specified with the statement BASE CLASS {Name}, but after the IMPORT statement where the ancestor class is listed.

The BASE CLASS ... statement is not ended with a dot or semicolon.

 

Завершается класс оператором END в отдельной строке.

 

A class is always ended with a standalone statement END located in a separate line.

 

До оператора END могут встречаться:

  • операторы определения перечислений
    ENUM {
    имя|уточнение} :
        '
    НАИМЕН|ОВАНИЕ1'
        'НАИМЕН|ОВАНИЕ2'

        ...  .
  • операторы описания структур (записей)
    RECORD {имя|уточнение} :
        поле1
        поле2

        ... .
  • операторы описания таблиц
    TABLE
    Имя|уточнение : {запись}
        NAME "
    имя"
        COUNTER(
    список)
        NOTNULL(список)
        NAMES(
    поле = "имя", ...)
    .
  • декларации полей
    ТИП Имя|уточнение [размер] = инициализация, модификатор
  • декларация конструктора
    CONSTRUCT :
        ТЕЛО .
  • декларация деструктора
    DESTRUCT :
        ТЕЛО .
  • декларации статических функций
    FUNCTION Имя|уточнение(параметры) ==> ТИП_РЕЗУЛЬТАТА,
        модификатор1, модификатор2,
    ... :
        ТЕЛО .
  • декларации методов
    METHOD Имя|уточнение(параметры) ==> ТИП_РЕЗУЛЬТАТА,
        модификатор1, модификатор2,
    ... :
        ТЕЛО .
  • декларации переопределённых функций
    OVERRIDE Имя(параметры) ==> ТИП, модификатор1, ... :
       
    ТЕЛО .
  • функции тестирования
    TEST Имя|уточнение(параметры) ==> ТИП_РЕЗУЛЬТАТА :
        
    ТЕЛО .
  • блочные комментарии
    --------------------------- 'текст'
  • директивы NATIVE
    NATIVE: "
    код специфичный для платформы" .
  • операторы TODO
    TODO: "
    строка" .
 

Before the END statement following statements/blocks can be found:

  • enumeration declarations
    ENUM {name|detailed} :
         'NAME|DETAILED1'
         'NAME|DETAILED2'

         ...  . 
  • structure definitions
    RECORD {name|detailed} :
           Field1
           Field2

           ...   .
  • table definitions
    TABLE
    Name|detailed : {запись}
        NAME "name"
        COUNTER(list
    )
        NOTNULL(list)
        NAMES(field
    = "name", ...)
    .
  • field declarations
    TYPE Name|detailed [size] = initialization, modifier
  • constructor declaration
    CONSTRUCT:
        BODY .
  • destructor declaration
    DESTRUCT:
        BODY .
  • static functions declarations
    FUNCTION Name|detailed(parameters) ==> RESULT_TYPE, modifier1,
    modifier2,
    ... :
        BODY .
  • methods declarations
    METHOD Name|detailed(parameters) ==> RESULT_TYPE, modifier1,
    modifier2,
    ... :
        BODY .
  • overridden methods
    OVERRIDE Name(parameters) ==> TYPE, modifier1,
    ... :
        BODY .
  • test functions
    TEST Name|detailed (parameters) ==> TYPE :
         BODY .
  • block comments
    --------------------------------- 'text'
  • native code directives
    NATIVE: "code specific for a platform" .
  • to-do statements
    TODO "text" .

$$STOP!