Разработка аспектно-ориентированного расширения для языка Kotlin Борис Скрипаль Владимир Ицыксон Санкт-Петербургский политехнический Санкт-Петербургский политехнический университет Петра Великого университет Петра Великого Email: skripal@kspt.icc.spbstu.ru Email: vlad@icc.spbstu.ru Аннотация—В статье описывается разработка аспектно- Наличие существенного числа новых конструкций не ориентированного расширения для языка Kotlin. Kotlin — мо- позволяет использовать уже готовые АОП-расширения лодой мультипарадигменный язык программирования, быст- для JVM-совместимых языков, поэтому аспектно- ро набирающий популярность. Однако для полноценной кон- куренции с существующими языками необходима реализа- ориентированное расширение для языка Kotlin необходимо ция многих возможностей, уже существующих для традици- разрабатывать, специально ориентируясь на особенности онных языков. Одна из таких возможностей — аспектно- языка Kotlin. ориентированное программирование. В статье на основе ана- Оставшаяся часть статьи организована следующим обра- лиза существующих аспектно-ориентированных расширений зом. В втором разделе приведено общее описание аспектно- для различных объектно-ориентированных языков разраба- тывается программный прототип, позволяющий использовать ориентированной парадигмы, в третьем разделе представле- аспектно-ориентированный подход при написании программ ны актуальные реализации аспектно-ориентированных рас- на языке Kotlin. Для этого проектируется язык описания аспек- ширений. Четвертый раздел посвящен описанию разрабаты- тов, реализуются методы внедрения сквозной функционально- ваемого расширения для языка Kotlin. В пятом разделе про- сти. Созданный прототип протестирован на серии примеров. водится тестирование расширения на реальных проектах. В Тестирование показало корректность предложенного подхода и работоспособность прототипа. заключении приводятся направления дальнейшего развития. I. В В ЕД ЕН ИЕ II. А С П Е К Т Н О - О Р И Е Н Т И Р О В А Н Н Ы Й П ОД ХО Д Аспектно-ориентированный подход (АОП) был предло- При использовании АОП, сквозная функциональность ин- жен как решение проблемы описания сквозной функцио- капсулируется в отдельные сущности, называемые аспекта- нальности в объектно-ориентированных программах. Впер- ми (aspects). Каждый аспект состоит из советов (advices) вые подход был представлен в 1997 году Грегором Кичале- и срезов (pointcuts). Совет — сущность, содержащая в себе сом в работе «Aspect-oriented programming» [1]. В предло- непосредственно сквозную функциональность (код совета), женном подходе сквозная функциональность описывается а также способ её внедрения в программный код. Срез — отдельно от объектно-ориентированного кода программы и описание множества точек внедрения советов. Типовыми внедряется на этапе компиляции. Такое разделение позво- способами внедрения сквозной функциональности являют- ляет не только компактно описывать сквозную функцио- ся: нальность, но и делать её внедрение прозрачным для про- граммиста. • вставка совета до точки внедрения; Парадигма АОП предложила элегантное решение для ря- • вставка совета после точки внедрения; да задач, как, например, протоколирование и трассировка • вставка совета после возникновения исключительной программ, работа с транзакциями, обработка ошибок, а так- ситуации; же некоторых других. АОП стал интенсивно развиваться и, • вставка совета вместо точки внедрения. в настоящий момент, аспектно-ориентированные расшире- Вставка кода совета может производиться статически и ния созданы для большинства объектно-ориентированных динамически. При статическом способе внедрения советов, языков программирования, как, например, C++ [2], C# [3], сквозная функциональность внедряется или на этапе сборки Java [4], [5], Python [6] и т.п. (модификация исходных кодов программы и модификация В данной статье мы представляем аспектно- промежуточного представления в процессе компиляции), ориентированное расширение для нового языка или же, сразу после сборки, например, путем модифика- программирования Kotlin. Язык Kotlin — молодой ции байт-кода (для программ, работающих поверх JVM). мультипарадигменный язык программирования, Основным преимуществом данного подхода является от- разрабатываемый компанией JetBrains. Основная цель сутствие затрат на внедрение советов во время выполнения языка Kotlin — быть компактной, выразительной и программы [7], однако, при изменении одного совета, будет надежной заменой языка Java. При этом язык обеспечивает необходима повторная сборка всего проекта. В связи с этим, полную совместимость с программами на языке Java. статический способ внедрения используется как правило в тех случаях, когда сквозная функциональность необходима B. SpringAOP для корректной работы программы. Другим популярным АОП-расширением для языка Java При динамическом внедрении сквозной функционально- является SpringAOP — расширение, входящее в состав сти код советов применяется непосредственно в процессе фреймворка «Spring Framework». Первая версия данного выполнения программы. Одним из способов динамического расширения была представлена в 2005 году, последняя внедрения советов является создание прокси-объектов [8], (5.0.0.M5) — в феврале 2017 года. Для описания аспектов в которые перехватывают исполнение программы, позволяя SpringAOP используются специальные аннотации, размеча- выполнять код совета до, после или вместо точки внедре- ющие классы и их методы, как аспекты, советы и срезы [5]. ния. Такой способ внедрения аспектов не требует повтор- Также, как и в AspectJ, аспект может содержать не только ной сборки всего проекта после изменения аспектов, однако описание срезов или советов, но и обычные в понимании имеет меньшую производительность. языка Java переменные и методы. SpringAOP поддерживает только динамическое внедре- III. О Б ЗО Р С УЩ ЕС ТВ УЮЩИХ ние аспектов в код. Основным способом применение аспек- А С П Е К ТН О -О Р ИЕ НТИРОВАННЫ Х тов в SpringAOP является связывание при помощи прокси- Р А СШ ИР ЕНИЙ объектов. Перед разработкой АОП-расширения для языка Kotlin Начиная с версии 5.0, Spring Framework добавил под- рассмотрим существующие на рынке АОП-решения и их держку языка Kotlin [10], что позволяет учитывать execution основные особенности. функции, а также проверку на nullability при использовании SpringAOP. A. AspectJ C. AspectC++ AspectJ — первое аспектно-ориентированное расширение Третьим рассматриваемым АОП-расширением является для языка Java, оно было представлено в 2003 году [9] и раз- AspectC++ [2] — АОП-расширение для программ на языке вивается до сих пор1 . AspectJ расширяет грамматику языка C++. Первая реализация AspectC++ была представлена в Java, предоставляя дополнительные языковые конструкции 2001 году, последняя — в марте 2017 года. В качестве сре- для описания аспектов. В отличие от классов описание ас- зов, в AspectC++ могут выступать как статические сущно- пекта в AspectJ начинается с ключевого слова aspect. Сам сти (классы, структуры, функции и т.д.), так и динамические аспект имеет уникальное имя и состоит из тела, которое сущности (вызов и выполнение функций, создание и удале- содержит описание срезов и советов, а также может исполь- ние объектов) [11]. В данном расширении, аспект выступает зовать переменные и методы языка Java. Описания срезов как отдельная сущность, обозначающая ключевым словом могут задаваться как отдельно от совета (в таком случае им aspect и содержащая в себе описание советов и именованных необходимо задавать идентификатор, уникальный в рамках срезов. Основным способом внедрения аспектов, используе- аспекта), так и, непосредственно, при описании совета. Спо- мым в AspectC++ является статическое внедрение аспектов соб внедрения кода совета относительно точки внедрения на уровне исходных кодов [12]. задается при описании совета с помощью ряда ключевых слов: before (после точки внедрения), after (перед точкой D. PostSharp внедрения) и т.д. Также в AspectJ существует возможность описания аспектов при помощи специальных аннотаций над Еще одной реализацией АОП является PostSharp — классами языка Java. При таком подходе в качестве аспекта АОП-фреймворк для программ, написанных на языке C#. выступает класс, снабженный аннотацией @Aspect, а среза- PostSharp было представлен в 2004 году [3], как свободная ми и советами выступают методы данного класса, имеющие библиотека для языка C#, однако в 2009 году данное рас- аннотации @Pointcut или же специальными аннотациями со- ширение стало проприетарным. На момент написания ста- ветов (например, @Before) соответственно. Описание сре- тьи последняя стабильная версия расширения 4.3.29 была зов также задается внутри аннотаций. представлена в феврале 2017 года. Для описания аспектов AspectJ поддерживает статический и динамический спо- в PostSharp существует ряд классов, обеспечивающих внед- собы внедрения аспектов [4]. Статическое внедрение аспек- рения кода совета в программу. Каждый из таких классов тов может производиться, как на уровне исходных кодов, определяет некоторый набор способов включения сквозной так и сразу после компиляции программы (внедрение кода функциональности относительно точки внедрения [13]. Для советов в байт-код скомпилированной программы). Дина- реализации аспектов, необходимо переопределить соответ- мическое внедрение аспектов производится непосредствен- ствующие методы этого класса, а также прописать правила но перед тем, как JVM загружает файл класса, что позво- формирования среза внутри специальных аннотаций данно- ляет избежать временных затрат на внедрение аспектов во го класса. время выполнения программы. PostSharp поддерживает как статический, так и дина- мический способы внедрения аспектов. Для динамическо- 1 На момент написания статьи последняя доступная версия 1.8.10 дати- го применения аспектов могут использоваться как прокси- рована 12 декабря 2016 г. объекты, так и перехват момента загрузки файла в память, после чего аспекты применяются непосредственно к бинар- ми, а также нагляднее отделяет объектно-ориентированную ному файлу. Статическое внедрение аспектов может произ- функциональность от сквозной. водиться как на уровне исходных кодов, так и во время ком- Для адаптации AspectJ к языку Kotlin в синтаксис AspectJ пиляции. При применении аспектов во время компиляции были внесены следующие изменения: используется MSIL — промежуточное представление, со- • способ описания методов был изменен в соответствии здаваемое в процессе компиляции программ для платформы с правилами языка Kotlin; .NET. MSIL является независимым от процессора набором • стандартные типы языка Java были заменены на стан- инструкций, который впоследствии преобразуется в набор дартные типы языка Kotlin; кодов для конкретного процессора. Такой подход позво- • в соответствии с правилами языка Kotlin изменены мо- ляет удобно анализировать целевую программу, а также дификаторы полей и методов; избавляет от необходимости поддерживать корректность • добавлена возможность задавать атрибуты аргументов исходных кодов программы после внедрения аспектов, что методов; необходимо делать при модификации на уровне исходных • добавлена поддержка функций-расширений (extension кодов. functions) и подставляемых функций (inline functions). По результатам анализа ряда популярных АОП- Описание аспекта начинается с ключевого слова aspect расширений можно сделать вывод о том, что не смотря на и состоит из идентификатора аспекта и тела аспекта. Тело схожую функциональность, расширения сильно отличаются аспекта может содержать в себе описание срезов и советов. как способами описания аспектов, так и способами их Описание среза начинается с ключевого слова pointcut и внедрения. Данные различия обусловлены не только состоит из идентификатора среза и правила, в соответствии особенностями языка программирования, для которого с которым производится формирования среза. предназначено расширение, но и стремлением сделать Правило формирования среза по сути является описани- синтаксис описания аспектов как можно более удобным и ем множества точек внедрения, для задания которого ис- понятным для разработчика. пользуются логические операции и специальные ключевые слова, например, execution или call, указывающие на опре- IV. Р АЗРА Б ОТКА деленную группу мест в программном коде. Допускается АС П Е КТН О- ОРИ ЕН ТИ РОВАННОГ О описывать одни срезы с использованием других. РА СШ И РЕН И Я Д Л Я ЯЗЫКА KOTL IN Для указания множества методов, входящих в срез, ис- При реализации аспектно-ориентированного расширения пользуются следующие механизмы: необходимо сформировать синтаксис аспектов и опреде- • модификаторы видимости с логическими операторами лить механизмы внедрения аспектов. (например, можно выделить все не public методы); • класс, к которому принадлежит метод; A. Разработка синтаксиса описания аспектов • имя метода или его часть; Описание аспектов является расширением языка про- • список аргументов метода с атрибутами; граммирования и должно позволять в удобной и понятной • тип возвращаемого значения. форме задавать все сущности АОП: аспекты, советы, срезы Описание совета состоит из задания способа применения и т.п. В этой работе мы приняли решение не разрабатывать совета (например, before или after), правила формирования специализированный синтаксис аспектов для языка Kotlin, а среза и кода совета. воспользоваться синтаксисом описания аспектов, использу- Пример описания аспекта приведен в листинге 1. емый в AspectJ для языка Java, расширив его необходимыми aspect A { для языка Kotlin конструкциями. Такой выбор был сделан p o i n t c u t fooPC ( ) : e x e c u t i o n ( f u n Foo . * ( ) ) по нескольким причинам: p o i n t c u t printPC ( ) : c a l l ( p u b l i c fun k o t l i n . io . p r i * ( ! Any ) ) • синтаксис описания аспектов, используемый в AspectJ, является очень удобным для программиста; a f t e r ( ) : fooPC ( ) && p r i n t P C ( ) { • грамматика AspectJ, описанная на языке ANTLR4, на- p r i n t l n (” Hello a f t e r ! ! ” ) } ходится в свободном доступе и может быть использо- вана для разработки языка аспектов для языка Kotlin; b e f o r e ( ) : fooPC ( ) && p r i n t P C ( ) { • AspectJ является одним из самых популярных p r i n t l n (” Hello before ! ! ” ) } аспектно-ориентированных расширений для языка } Java [14] и знаком многим разработчикам. Листинг 1. Пример описания аспекта Учитывая, что в AspectJ описание аспектов может произ- водится двумя способами: при помощи специальных анно- Приведенный в листинге аспект содержит описание двух таций над классами и как отдельные сущности, было решено срезов: fooPC и printPC. Срез fooPC включает в себя все использовать второй способ. Такой выбор был сделан ввиду места вызовов функций и инициализации переменных внут- того, что такой способ описания аспектов, по мнению авто- ри всех методов класса Foo. Срез printPC включает в себя ров, является менее избыточным, по сравнению с аннотация- все места вызовов публичных методов пакета kotlin.io, имя которых начинается с pri, принимающих один аргумент, тип Внедрение аспектов происходит в несколько этапов, схе- которого отличается от Any. Далее описываются два сове- матически изображенных на рисунке 1. та: первый вставляет код совета (вызов метода println) до Первым этапом является построение PSI — промежу- всех точек внедрения, которые принадлежат одновременно точного представления проекта, состоящего из набора вир- к двум срезам fooPC и printPC, второй — после. После туальных файлов, соответствующих исходными файлам, а применения совета к программе во всех местах вызовов также из прочей информации о проекте (конфигурация, методов, удовлетворяющих следующим условиям: путь до JDK и т.п.). Каждый из этих файлов содержит де- • вызов происходит внутри методов, принадлежащих рево разбора программного кода и информацию о файле. классу Foo; Каждый элемент дерева разбора содержит в себе текст со- • вызываемый метод имеет модификатор public и при- ответствующего элемента, ссылки на потомков и различную надлежит к пакету kotlin.io; сопровождающую информацию. Одним из таких полей яв- • имя вызываемой метода начинается с pri; ляется «userMap» типа KeyFMap — структура в, которую • метод принимает единственный аргумент, тип которо- могут быть записаны различные пользовательские данные. го отличается от «Any». На рисунке 1 схематически представлен процесс внедрения аспектов в программный код. до вызова метода будет выведена на печать строка «Hello Вторым этапом является чтение файлов с описаниями after!!», а после — «Hello before!!». аспектов и формирование модели аспектов, состоящих из На момент написания статьи реализованы следующие воз- срезов и советов. Каждый экземпляр совета и среза содер- можности, существующие в AspectJ: жит: • Структуры, используемые при описании срезов: • уникальный идентификатор, используемый для размет- – call — вызов заданного метода; ки PSI; – execution — выполнение заданного метода; • дерево разбора логического выражения, используемое – target — вызов метода у экземпляра указанного при анализе принадлежности точки срезу. класса; Также экземпляр совета содержит в себе код совета, при- • Способы внедрения советов: веденный к виду промежуточного представления для бо- – before — вставка кода совета перед точкой внед- лее удобной модификации PSI. Дерево разбора в качестве рения; нетерминальных узлов содержит в себе логические опера- – after — вставка кода совета после точки внедре- ции «и», «или», «не». Терминальными же узлами выступают ния; или сигнатуры, используемые для описания срезов, или же – around — вставка кода совета до и после точки идентификаторы других срезов. внедрения. Формирование набора точек внедрения также происходит в несколько шагов. На первом шаге, каждый узел PSI про- B. Внедрение аспектов веряется на соответствие каждому из отдельно описанных внутри совета срезов. В случае, если узел подходит данному Язык Kotlin имеет ряд оригинальных языковых конструк- срезу, то в структуру userMap добавляется идентификатор ций (extension функции, специфичные лямбда-функции и этого среза. На втором шаге, после того, как дерево было т.п.), при этом основной целевой платформой компиляции размечено идентификаторами срезов, для каждого совета для языка Kotlin является JVM. Как результат — все спе- проверяется, можно ли его применить к данному узлу де- циальные конструкции Kotlin преобразуются в стандартный рева. Если можно, то происходит внедрение кода совета в байт-код, который имеет одинаковую структуру и для Java-, соответствующую позицию относительно точки внедрения. и для Kotlin-программ. Из-за этого поиск некоторых струк- При внедрении в PSI код советов оборачивается в лямбда тур языка Kotlin в байт-коде становится затруднительным функцию run, что позволяет разрешать сложные случаи, и, как следствие, динамическое внедрение кода советов при например, при последовательном вызове нескольких функ- загрузке файлов в JVM становится практически невозмож- ций без создания большого числа дополнительных промежу- ным. По той же причине статическое внедрение советов в точных переменных. Для наглядности, рассмотрим участок байт-код программы также является очень сложной зада- кода в листинге 2. чей. ... Таким образом, единственным разумным способом внед- v a l r e s = A. foo ( ) . bar ( ) . baz ( ) рения аспектов является внедрение аспектов в исходный ... код программы или в модель программы во время компи- Листинг 2. Пример целевой точки внедрения ляции. Разработчики языка Kotlin предусмотрели специальную При необходимости применить совет непосредственно по- структуру данных для работы с программным кодом — сле вызова функции bar() целевая функция оборачивается в Program Structure Interface (PSI). В нашем проекте мы ис- метод run, значение, возвращаемое функцией присваивается пользуем PSI для внедрения объектов на этапе компиляции некоторой промежуточной переменной, после чего встав- проекта. ляется код совета и затем из блока возвращается перемен- Рис. 1. Процесс внедрения аспектов в программный код при компиляции ная, содержащая результат, возвращенный функцией bar, 1) составить набор аспектов, которые будут применять- к которой был применен совет. Результат преобразования ся к целевой программе; представлен в листинге 3. 2) составить набор эталонных файлов, представляющих ... из себя исходные файлы целевой программы, к кото- val r e s = A. foo ( ) . run { рым вручную применены описанные выше аспекты; val buf = bar ( ) 3) модифицировать PSI целевой программы, а именно / / a d v i c e code buf произвести составление модели аспектов, разметку } . baz ( ) PSI и применить их к PSI проекта; ... 4) сформировать на основе модифицированных вирту- Листинг 3. Пример внедрения кода с использованием функции run альные файлов исходные файлы на языке Kotlin; 5) сравнить на уровне токенов полученные файлы с эта- Данный подход решает проблему разнесения вложенного лонными исходными файлами, в которых аспекты вызова методов, при котором пришлось бы заводить мно- применены вручную. жество временных переменных, а также контролировать После успешной проверки корректности работы на возвращаемые результаты методов. К недостаткам данного уровне функций, необходимо убедиться в том, что после подхода можно отнести то, что при изменении аспекта, тре- применения аспектов программа остается корректной и ра- буется полная перекомпиляция проекта. Однако, при таком ботает согласно нашим ожиданиям. Это можно сделать, на- подходе, нет необходимости производить дополнительные пример, поместив в код совета вывод отладочных сообще- действия при запуске для корректной работы полученного ний, и после выполнения программы необходимо сравнить jar-файла. результат работы программы с ожидаемым. V. Т Е С Т И РО В АН И Е РАЗ РАБОТАННОГ О На начальных этапах работы, для тестирования были со- П РО ТОТ ИП А зданы простые примеры программ (несколько классов с 2-3 функциями в каждом из них, суммарный объем — несколь- Для того чтобы убедиться в работоспособности изло- ко десятков строк кода). Впоследствии была проведена женного выше подхода, был реализован прототип АОП- проверка на программах студентов, изучающих язык Kotlin расширения для языка Kotlin. Проверка работоспособности (суммарный размер каждого проекта достигает несколько разработанного подхода проводится с помощью тестирова- сотен строк кода). Время внедрения аспектов к программам ния. Сначала проверяется корректность реализации отдель- размером в несколько сотен строк кода составило около 1-2 ных функций, затем проводится проверка приложений, к секунд. которым применили аспекты. В ходе тестирования ошибок обнаружено не было, что Проверка корректности реализации отдельных функций свидетельствует о работоспособности подхода и прототипа. включает в себя: Рассмотрим пример протоколирования программы при • тестирование разбора логического выражения, описы- помощи разработанного прототипа. В качестве целевой про- вающего срез; граммы было выбрано приложение, вычисляющее значение • проверка правильности выделения точек внедрения; арифметического выражения, заданного в файле. В качестве • проверка внедрения кода советов в PSI целевой про- входных данных приложение принимает имя файла, в кото- граммы. ром записано выражение, а также список значений парамет- Из-за того, что сама по себе проверка PSI является слож- ра x, используемые при вычислении выражения. Результатом ной задачей, было решено проверить корректность работы работы является ассоциативный массив в котором ключем на уровне функций следующим образом: является значение параметра, а значением — результат вы- числения выражения при подстановке данного значения в при написании программ на языке Kotlin. На основе AspectJ качестве значения параметра. было реализовано расширение, которое, используя статиче- Программа работает по следующему алгоритму: первым ское внедрение советов, модифицирует модель PSI. Работо- вызывается метод pExpr, принимающий имя файла в ко- способность подхода была показана на ряде примеров. тором записано выражение и список значений параметра. Направления дальнейшей работы: Внутри метода pExpr в цикле вызывается метод calc, при- • расширение синтаксиса аспектов для поддержки всех нимающий значение параметра и возвращающий вычислен- возможностей языка Kotlin; ное значение выражения. После чего значение параметра и • оптимизация процедур внедрения аспектов; результат вычисления записывается в ассоциативный мас- • более глубокое тестирование разработанного про- сив, возвращаемый функцией pExpr в качестве результата. граммного обеспечения. Для того, чтобы зафиксировать в журнале время начала и завершения работы метода calc воспользуемся аспектом, Список литературы представленным в листинге 4. [1] G. Kiczales, J. Lamping, A. Mendhekar, C. Maeda, aspect A { C. Lopes, J. Loingtier и J. Irwin, “Aspect-oriented p o i n t c u t pExprPC ( ) : e x e c u t i o n ( f u n pExpr ( S t r i n g , programming,” European Conference on Object- L i s t < I n t > ) : Map< I n t , I n t > ) Oriented Programming (ECOOP), 1997. p o i n t c u t calcPC ( ) : c a l l ( fun E xpr es si on . c a l c ( I n t ) : Int ) [2] (2017). The home of aspectc++. англ., url: http://www. aspectc.org/Home.php. b e f o r e ( ) : pExprPC ( ) && c a l c P C ( ) { [3] (2017). Postsharp documentation. англ., url: http://doc. v a l l = j a v a . u t i l . l o g g i n g . L o g g e r . g e t L o g g e r ( ” ALog ”) postsharp.net/. l . i n f o ( ” S t a r t $ { System . c u r r e n t T i m e M i l l i s ( ) } ” ) [4] (2017). Aspectj documentation. англ., url: http://www. } eclipse.org/aspectj/docs.php. a f t e r ( ) : pExprPC ( ) && c a l c P C ( ) { [5] (2017). Aspect oriented programming with spring. англ., v a l l = j a v a . u t i l . l o g g i n g . L o g g e r . g e t L o g g e r ( ” ALog url: https://docs.spring.io/spring/docs/current/spring- ”) framework-reference/html/aop.html. l . i n f o ( ” F i n i s h $ { System . c u r r e n t T i m e M i l l i s ( ) } ” ) } [6] (2017). Aspect oriented programming — spring python. } англ., url: http://docs.spring.io/spring- python/1.2.x/ Листинг 4. Пример аспекта, используемого для логирования вызова метода sphinx/html/aop.html. calc [7] M. Forgac и J. Kollar, “Static and dynamic approaches to После применения аспекта, место вызова метода calc, weaving,” 5th Slovakian-Hungarian Joint Symposium on представленное в листинге 5 будет преобразовано к виду, Applied Machine Intelligence and Informatics, 2007. приведенному в листинге 6. [8] W. Gilani и O. Spinczyk, “A family of aspect dynamic for ( value in values ) { weavers,” Proceedings of the 2003 Dynamic Aspect r e s u l t [ value ] = expr . calc ( value ) Workshop (DAW04 2003), 2003. } [9] G. Kiczales, E. Hilsdale, J. Hugunin, J. Kersten M. Palm Листинг 5. Место вызова метода calc до применения аспекта и W. Griswold, “An overview of aspectj,” European Conference on Object-Oriented Programming (ECOOP), for ( value in values ) { 2001. r e s u l t [ value ] = expr . run { v a l ____a = r u n { [10] (2017). Introducing kotlin support in spring framework v a l l = j a v a . u t i l . l o g g i n g . Logger . getLogger ( ” 5.0. англ., url: https://kotlin.link/articles/Introducing- ALog ” ) Kotlin-support-in-Spring-Framework-5-0.html. l . i n f o ( ” S t a r t $ { System . c u r r e n t T i m e M i l l i s ( ) } ” ) calc ( value ) } [11] O. Spinczyk, “Documentation: Aspectc++ language v a l l = j a v a . u t i l . l o g g i n g . L o g g e r . g e t L o g g e r ( ” ALog ” ) reference,” Pure-systems, 2017. l . i n f o ( ” F i n i s h $ { System . c u r r e n t T i m e M i l l i s ( ) } ” ) [12] ——, “Aspectc++ — a language overview,” Friedrich- ____a } } Alexander University Erlangen-Nuremberg Computer Science 4, 2005. Листинг 6. Место вызова метода calc после применения аспекта [13] (2017). Postsharp. aspects namespace. англ., url: http:// Как видно из листинга 6, вызов метода был помещен doc.postsharp.net/n_postsharp_aspects. внутрь лямбда функции run согласно ожиданиям. После [14] H. Kurdi, “Review on aspect oriented programming,” запуска, в журнал выводятся сообщения о времени начала International Journal of Advanced Computer Science и окончания работы метода calc, что соответствует ожида- and Applications, 2013. ниям. VI. З А КЛ Ю Ч ЕНИЕ В ходе данной работы был разработан подход, позволя- ющий использовать аспектно-ориентированную парадигму Aspect-oriented extension for the Kotlin programming language Boris Skripal, Vladimir Itsykson This paper present an aspect-oriented extension for the Kotlin programming language. Kotlin is a new multi-paradigm programming language that is rapidly gaining popularity. However, to be competitive with the existing programming languages it is necessary to implement many extensions already existing for the traditional programming languages. One of such extensions is an aspect-oriented approach. In the paper, after the analysis of the aspect-oriented extensions for the different object-oriented languages, we have developed a program prototype, which allows using the aspect-oriented approach with Kotlin programming language. We have developed a grammar for describing aspects and have created extension of Kotlin compiler for weaving cross-cutting functionality. The developed extension has been successfully verified on a test suite.