Справочное руководство по Ada 95
3.9.2 Диспечерские операции помеченных типов
Примитивные подпрограммы помеченного типа называются диспечерскими операциями. Диспечерскую операцию можно вызвать, используя статически определенный управляющий тег, в этом случае тело, которое будет выполнено, определяется во время компиляции. В качестве альтернативы управляющий тег может быть динамически определен, в этом случае вызов диспетчирует к телу, которое определяется во время выполнения; такой вызов называется диспечерским вызовом. Как описано ниже, свойства операндов и контекст конкретного вызова диспечерской операции определяют, как определяется управляющий тег, и, следовательно, является ли вызов диспечерским вызовом. Полиморфизм времени выполнения достигается, когда диспечерская операция вызывается диспечерским вызовом.
Статическая семантика
Вызов диспечерской операции — это вызов, имя или префикс которого обозначает объявление примитивной подпрограммы помеченного типа, то есть диспечерской операции. Управляющий операнд в вызове диспечерской операции помеченного типа T — это операнд, соответствующий формальному параметру типа T или анонимного типа доступа с указанным типом T; соответствующий формальный параметр называется управляющим формальным параметром. Если управляющий формальный параметр является параметром доступа, управляющим операндом является объект, обозначаемый фактическим параметром, а не сам фактический параметр. Если вызов осуществляется для (примитивной) функции с типом результата T, то вызов имеет управляющий результат — контекст вызова может управлять диспетчированием.
Имя или выражение помеченного типа являются либо статически помеченными, динамически помеченными, или не определены по тегу, в зависимости от того, когда они используются в качестве управляющего операнда, тег, который управляет диспетчированием, определяется статически типом операнда (конкретным), динамически его тегом во время выполнения или из контекста. Квалифицированное выражение или выражение в скобках являются статически, динамически или неопределенно помеченными в соответствии с их операндом. Для других видов имен и выражений это определяется следующим образом:
- Имя или выражение статически помечены, если оно имеет конкретный помеченный тип и, если это вызов с управляющим результатом, имеет по крайней мере один статически помеченный управляющий операнд;
- Имя или выражение динамически помечены, если оно имеет тип класса или это вызов с управляющим результатом и по крайней мере один динамически помеченный управляющий операнд;
- Имя или выражение не определены по тегу, если это вызов с управляющим результатом, все управляющие операнды (если таковые имеются) не определены по тегу.
Преобразование типа является статически или динамически помеченным в зависимости от того, является ли тип, определяемый маркером подтипа, конкретным или широко распространенным соответственно. Для объекта, обозначенного выражением, ожидаемый тип которого является анонимным типом доступа к конкретному помеченному типу, объект динамически помечен, если выражение, игнорируя окружающие скобки, имеет вид X'Access, где X имеет тип класса, или имеет вид new T'(...), где T обозначает подтип класса. В противном случае объект статически или динамически помечен в зависимости от того, является ли указанный тип выражения конкретным или широко распространенным соответственно.
Правила легальности
Вызов диспечерской операции не должен иметь как динамически помеченные, так и статически помеченные управляющие операнды.
Если ожидаемый тип для выражения или имени — это конкретный помеченный тип, то выражение или имя не должны быть динамически помечены, если они не являются управляющими операндами в вызове диспечерской операции. Аналогично, если ожидаемый тип для выражения — это анонимный тип доступа к конкретному помеченному типу, то объект, обозначаемый выражением, не должен быть динамически помечен, если он не является управляющим операндом в вызове диспечерской операции.
В объявлении диспечерской операции помеченного типа везде, где подтип помеченного типа появляется как подтип профиля (см. 6.1), он должен статически соответствовать первому подтипу помеченного типа. Если диспечерская операция переопределяет унаследованную подпрограмму, она должна быть совместима с подтипом унаследованной подпрограммы. Конвенция унаследованной или переопределенной диспечерской операции — это конвенция соответствующей примитивной операции родительского типа. Явно объявленная диспечерская операция не должна быть типа Intrinsic.
Выражение по умолчанию для управляющего формального параметра диспечерской операции должно быть неопределенным по тегу. Управляющий формальный параметр, являющийся параметром доступа, не должен иметь выражение по умолчанию.
Данная подпрограмма не может быть диспечерской операцией для двух или более различных помеченных типов.
Явное объявление примитивной подпрограммы помеченного типа должно произойти до того, как тип будет заморожен (см. 13.14). Например, новые диспечерские операции не могут быть добавлены после существования объектов или значений типа, а также после получения расширения записи из него или после тела.
Динамическая семантика
Для выполнения вызова диспечерской операции типа T, значение управляющего тега определяет, какое тело подпрограммы будет выполнено. Значение управляющего тега определяется следующим образом:
- Если один или несколько управляющих операндов статически помечены, тогда значение управляющего тега статически определяется как тег T.
- Если один или несколько управляющих операндов динамически помечены, тогда значение управляющего тега не определяется статически, а определяется тегами управляющих операндов. Если имеется более одного динамически помеченного управляющего операнда, выполняется проверка, что у них все один и тот же тег. Если эта проверка не пройдена, Constraint_Error поднимается, если вызов является функцией, имя которой обозначает объявление оператора равенства (предопределенного или пользовательского), который возвращает Boolean, в этом случае результат вызова определяется как указывающий на неравенство, и никакое тело подпрограммы не выполняется. Эта проверка выполняется до вычисления любых управляющих операндов, не определенных по тегу.
- Если все управляющие операнды не определены по тегу, то:
- Если вызов имеет управляющий результат и сам является (возможно, в скобках или квалифицированным) управляющим операндом вложенного вызова диспечерской операции типа T, тогда его значение управляющего тега определяется значением управляющего тега этого вложенного вызова;
- В противном случае значение управляющего тега статически определяется как тег типа T.
Для выполнения вызова диспечерской операции выполняемое тело — это тело соответствующей примитивной подпрограммы конкретного типа, идентифицированного значением управляющего тега. Тело явно объявленной диспечерской операции — это соответствующее явное тело подпрограммы. Тело неявно объявленной диспечерской операции, которая переопределена, — это тело переопределенной подпрограммы, даже если переопределение происходит в частях доступа. Тело унаследованной диспечерской операции, которая не переопределена, — это тело соответствующей подпрограммы родительского или предкового типа.
ПРИМЕЧАНИЯ
70 Тело, которое будет выполнено для вызова диспечерской операции, определяется тегом; не имеет значения, определяется ли этот тег статически или динамически, и не имеет значения, является ли объявление подпрограммы видимым в месте вызова.
71 Этот подраздел охватывает вызовы примитивных подпрограмм помеченного типа. Правила для тестов членства помеченных типов описаны в 4.5.2. Определение управляющего тега для оператора присваивания описано в 5.2.
72 Диспечерский вызов может диспетировать к телу, объявление которого не видно в месте вызова.
73 Вызов через значение доступа к подпрограмме никогда не является диспечерским вызовом, даже если значение доступа обозначает диспечерскую операцию. Аналогично, вызов, префикс которого обозначает объявление переименования подпрограммы, не может быть диспечерским вызовом, если переименование само не является объявлением примитивной подпрограммы.