ABAP в XXI веке (часть 1)
Это первая статья в небольшой серии публикаций, раскрывающих суть новшеств в языке ABAP версии 7.40 Здесь дана вводная информация по линейным описаниям, выводу типа и выражениям конструктора. Владение этими понятиями позволит вам добиться лаконичности кода ABAP.
Ключевое понятие
Язык программирования ABAP, который используется в SAP Business Suite, прошел длинный путь своего развития. Несмотря на наличие несомненных преимуществ (тесная интеграция с сервером и мощные возможности внутренних таблиц), он не был удобен для простых задач, например, для вычисления значения структурированного типа, поскольку ему недоставало поддержки регулярных выражений. В последних расширениях этот недостаток был устранен.
С развитием SAP HANA инновации для сервера ABAP стали появляться с прежней интенсивностью. Для версии 7.40, которая лежит в основе обновленного Business Suite (теперь S/4HANA), с 2013 года уже вышло несколько подверсий. Это первая статья в небольшой серии публикаций, раскрывающих суть новшеств в языке ABAP версии 7.40
Главными темами статьи являются линейные объявления переменных, вывод типа и выражения конструктора. В следующей статье мы рассмотрим расширения по работе с таблицами, создание таблиц, сокращение, группирование и другие аспекты. Как всегда, перед подробным изучением новых возможностей ABAP рекомендуем прочитать раздел «Release Specific Changes» (Изменения в версии) в прекрасно составленной онлайн-документации Хорста Келлера (Horst Keller), http://help.sap.com/abapdocu_740/en/index.htm?file=abennews-740.htm. В этой статье мы постараемся дополнительно рассмотреть историю вопроса, мотивацию и рациональное обоснование текущей ситуации, а также дадим ряд практических рекомендаций.
Примечание
На момент написания статьи актуальной версией пакета поддержки 7.40 (SP) с привязкой к версии ядра является SP8. При работе с более ранней версией ядра ABAP (SP 2 или 5) некоторые описанные здесь функции могут быть недоступны или доступны с ограничениями.
В этой версии ABAP мы не увидим новой доминирующей парадигмы или «модели программирования» (об этом можно не мечтать). Все расширения языка относятся к способам написания исходного кода программы, это позволяет добиться лаконичности и элегантности при обработке (структурированных) данных. После освоения новых возможностей языка, вы обязательно станете применять их практически в каждой строке своего кода.
Если в своей компании вы «динозавр, пишущий на ABAP», новый ритмичный вид строк ABAP поможет вам чувствовать себя увереннее с молодыми коллегами, работающими с новомодными языками. С другой стороны, если вы сами предпочитаете такие новомодные языки, описанные опции помогут вам менее болезненно – а, возможно, и с удовольствием – создавать элементы функциональности на ABAP.
Далекое прошлое – недавнее прошлое – 7.40
С момента появления в 1980-х в роли «макроассемблера» для обработки бизнес-отчетности язык ABAP не переставал совершенствоваться. Примечательно, что только к 2006 году (и позднее был преобразован в версию 7.02) язык избавился от самых ярких проявлений наследия ассемблера. Даже после добавления объектно-ориентированной концепции (примерно в 2000 году) можно было встретить подобные описания:
«ABAP – язык программирования четвертого поколения, предназначенный для бизнес-программирования высокого уровня. Поэтому на нем нельзя написать
IF x > n * 2.
n = f( n + 1 ).
x = n.
Вместо этого следует писать следующим образом:
DATA: n2 TYPE I, n1 TYPE i.
COMPUTE n2 = n * 2.
IF x > n2.
COMPUTE n1 = n + 1.
CALL METHOD f EXPORTING p = n1 RECEIVING r = n.
MOVE n TO x.
Обязательное использование переменных для промежуточных результатов и сходство с простыми предложениями на английском языке обеспечивает на выходе надежные и простые для восприятия программы.»
Если такая мысль вам не вполне ясна, знайте – вы не одиноки.
Прежде всего, следует заметить, что отсутствует как понятие языка для бизнес-программирования, так и особые потребности такого рода. Термин «бизнес» в сфере SAP в контексте программирования, можно косвенно перевести как «семантика» (в отношении темы, с которой работает компонент программного обеспечения). Как любой язык общего назначения, ABAP должен максимально упрощать выражение предполагаемой семантики. (Когда мы работаем с SAP, термин «бизнес» имеет и другие коннотации: программное обеспечение, как правило, очень сложное, выполняет серьезные задачи, обрабатывает массовые данные и работает с высокой степенью стабильности. Это справедливо для ABAP, но это не эксклюзивные бизнес-атрибуты.)
Во-вторых, подробный синтаксис с дурной славой COBOL жертвует компактностью и ортогональностью ради псевдоестественного внешнего вида. Тщательно подобранный набор лаконичных символов проще запомнить, чтобы не утонуть в море слов. Вот пара ключевых слов ABAP (взято непосредственно из COBOL), бесполезная избыточность которых весьма символична:
MOVE x TO n.
COMPUTE n = x + 1.
Между этими операторами не существует релевантной разницы, они оба относятся к присвоениям правостороннего (RHS) выражения и левосторонней (LHS) переменной. Кроме того, нет никакого обоснования для ограничения реальных выражений (т. е. состоящих из нескольких полей ) специальным оператором COMPUTE. Они должны быть разрешены в каждой позиции R-значения грамматики (т. е. при каждом считывании значения). Принудительное использование вспомогательных переменных даже в тривиальных ситуациях очень надоедает. Наконец, развитой язык должен включать в себя понятие L-значений (это выражения, которые выдают местоположение для присвоения другого значения).
В версии 7.02 ABAP сделал первый серьезный шаг, обеспечив выполнение вычислений напрямую в сравнениях, аргументах методов (как в примере выше) и многих других позициях R-значения. Добавлены строковые выражения, а также вложенные ячейки цепочек.
В версии 7.40 выражения можно использовать для еще большего числа операторов. Что еще более важно, полный набор операций в настоящее время доступен для обработки любых ABAP-типов в системе (атомарный элемент, структура, таблица и ссылка). Если посмотреть в документацию (ссылка дается выше), MOVE и COMPUTE там теперь указаны как устаревшие.
Абсолютное удобство: линейные объявления типов и вывод типа
Перед погружением в мир новых выражений рекомендую ознакомиться с еще одним связанным понятием, которое в некотором роде является более фундаментальным.
Как часто вы сталкивались с проблемой, когда необходимо вызвать метод и требуются переменные для получения возвращаемых параметров EXPORTING или RETURNING? Вы используете автодополнение для извлечения требуемых типов? Или переходите к описанию, копируете имена типов и вставляете их в вызывающий код? Возникает следующий вопрос: почему вы вообще должны об этом беспокоиться? ABAP-компилятору известен метод (иначе бы выводилось соответствующее сообщение), а значит, и все типы, используемые методом для проверки совместимости. Задачей компилятора является не только контролировать вас, но и помогать. В частности, он должен помогать предотвратить избыточность кода.
Понятие линейного объявления: Вы просто указываете намерение описать новую переменную и привязать ее к значению. Далее компилятор выбирает необходимый тип из контекста, например, сигнатуру метода. Это называется выводом типа. По сравнению с некоторыми другими языками (особенно функциональными) его возможности ограничены, но обычно достаточны. Типичный пример использования значащего имени переменной показан на Рис. 1. Средство автодополнения имеет те же возможности, что и компилятор, поэтому оно может сообщить, какого типа является переменная. (Если для ссылки вводится –> или для структуры вводится –, тогда, конечно же, предлагаются компоненты для автодополнения.)
Рис. 1. Автодополнению известен тип переменной с линейным описанием
Таким образом, синтаксис DATA(x) дает нам переменную x. В других местах синтаксис FIELD-SYMBOL(<x>) дает вам символьное поле (указатель в духе ABAP) с именем <x>. Самым наглядным является пример в цикле:
LOOP AT itab ASSIGNING FIELD-SYMBOL(<line>).
… <line>-comp = <line>-comp + 1. …
ENDLOOP.
Пробелы вокруг круглых скобок не ставятся. (Лексически эти ключевые слова родственны (без пробелов) «VALUE(x)» в описании параметра.)
Согласно общему правилу, в позиции грамматики ABAP активируется линейное описание, т.е. если переменная является L-значением, которое написано, но не считано, т.е. ранее не было выполнено декларирование использованной переменной. Таким образом, линейное объявление можно использовать после ключевого слова IMPORTING в вызове метода, но не после CHANGING. Исключениями из этого правила являются периферийные и устаревшие области ABAP (например, наборы данных или списки), для которых не используются ни выражения, ни описание. В одном операторе можно использовать несколько линейных объявлений:
meth( IMPORTING p1 = DATA(x)
p2 = DATA(y)
RECEIVING p3 = DATA(z) ).
Кстати, это наглядно показывает еще одно расширение: Теперь методы могут иметь параметры RETURNING вместе с параметрами EXPORTING и/или CHANGING. (На самом деле запрет на использование этой комбинации не имел смысла. Поскольку это императивный язык, любой метод может иметь побочные эффекты, даже если он называется функциональным. Явные параметры CHANGING фактически подтверждают это. Явные параметры EXPORTING компенсируют отсутствие кортежных результатов.)
Однако при попытке переместить DATA(z) в результаты LHS выдается синтаксическая ошибка (Рис. 2). Почему? Потому что теперь это не оператор вызова метода, а присвоение, использующее вызов метода RHS. Описания в середине выражения запрещены в гигиенических целях. (Сравните IF 0 = 1 AND meth( IMPORTING p = DATA(x) ) = 2. Часть после AND не анализируется, поэтому по существу здесь присутствует несвязанная (объявленная, но не используемая) переменная.)
Рис. 2. Линейное описание внутри выражений запрещено
Дополнительные сведения о правилах вывода, возможных ловушках и стиле
В Табл. 1 собраны наиболее эффективные линейные описания. Например, все операторы внутренних таблиц, предоставляющие доступ к строке таблицы, должны использоваться с ASSIGNING FIELD-SYMBOL(<x>), INTO DATA(x) и REFERENCE INTO DATA(x).
Линейное описание |
Выводимый тип |
|||
---|---|---|---|---|
DATA(x) = y. |
Тип y |
|||
DATA(x) = ‘abcd’. |
C(4) |
|||
DATA(x) = y && ‘~’. |
STRING |
|||
READ TABLE itab INDEX 1 REFERENCE INTO DATA(x). |
REF TO line-type of itab |
|||
ASSIGN 100 TO FIELD-SYMBOL(<x>). |
I |
|||
ASSIGN lcl=>(a) TO FIELD-SYMBOL(<x>). |
DATA (generic) |
|||
CATCH cx INTO DATA(x). |
REF To cx |
|||
FIND ALL OCCURRENCES OF a IN b MATCH COUNT DATA(x) RESULTS DATA(y). |
x : I, y : MATCH_RESULT_TAB |
|||
SPLIT blob AT null INTO TABLE DATA(x) IN BYTE MODE. |
STANDARD TABLE OF XSTRING |
|||
GET TIME STAMP FIELD DATA(x). |
TIMESTAMP |
|||
CONVERT TIME STAMP a TIME ZONE b INTO DATE DATA(x) TIME DATA(y). |
x : D, y : T |
|||
SELECT … INTO TABLE @DATA(x). |
Будет использоваться подходящий тип. (Описание новых выражений версии Open SQL 7.40 будет раскрыто дополнительно в следующей статье]) |
Табл. 1. Примеры линейных описаний
Любопытный случай представляет собой арифметика:
DATA(x) = 1 + y * f( z ).
Здесь компилятор определяет результат типа вычисления RHS, который является самым сильным числовым типом всех используемых операндов (по восходящей: I, P, F и DECFLOAT34).
Линейное описание может не сработать, поскольку иногда из контекста невозможно вывести какой-либо определенный тип. На Рис. 3 компилятор не располагает данными о том, какой тип следует использовать для x, поскольку формальным параметром (по иронии называемый DATA) является только STANDARD TABLE.
Рис. 3. Предупреждение компилятора о слишком обобщенном типе
Однако правила вывода предназначены для работы в любой возможной ситуации, где это целесообразно. Например, если параметр EXPORTING имеет родовой тип CSEQUENCE, привязанное к нему линейное описание получает тип STRING. Таким образом, если при наличии метода с параметром определенного типа (например, C(20) или STRING) позднее выполняется его обобщение (например, до CSEQUENCE), то существующие вызовы метода с линейными описаниями для этого параметра не будут ошибочны (как в примере с ошибкой синтаксиса на Рис. 3). Несмотря на то, что полная безопасность обобщения сигнатур не гарантируется, желательно стремиться к этому. Полная безопасность означает, что вызовы метода ни при каких условиях не могут получить ошибки синтаксиса при изменении параметра вызываемого метода с обобщением его типа. Подробнее об этом в разделе о CONV.)
В отношении постоянного значения RHS может показаться, что линейное описание эквивалентно инициализации переменной, но это не так. Рассмотрим фрагмент:
Оформите подписку sappro и получите полный доступ к материалам SAPPRO
Оформить подпискуУ вас уже есть подписка?
Войти