Очередная бета Realaxy ActionScript Editor содержит несколько новых языковых расширений. Мы уже рассказали о языке Traits, позволяющем использовать преимущества множественного наследования, теперь же обратимся к другой, не менее важной возможности — перегрузке и создании операторов.
Скачать редактор можно здесь.
Если вы еще не знакомы с RASE — обязательно прочитайте вводную статью.
При написании статьи в сборке 8144 был обнаружен баг. Если вы загрузили RASE beta 10 раньше 8 июня, то обязательно скачайте свежую версию.
Одна из основных фич, добавленных в RASE beta 10 — это перегрузка операторов.
Данная возможность, как и множественное наследование, является объектом споров среди последователей разных парадигм программирования.
Доводами в пользьзу перегрузки операторов являются компактность и естественность.
Компактность — a*b*c или a.multiply(b).multiply(с).
Естественность — при сложении нескольких переменных проще представить знак сложения, а не вызов метода. Например, складывая две переменные типа Point, мы ожидаем увидеть «point1 + point2», а не «point1.plus(point2)».
Противники перегрузки операторов указывают на потерю контроля над кодом. Не всегда понятно, где оператор перегружен, а где нет. Перегрузив оператор, мы меняем поведение существующего кода — и тут могут быть быть неожиданные эффекты.
В ActionScript(ECMA3) перегрузки операторов нет. Но они присутствуют в доступной на данный момент спецификации ECMA4. Перегрузки нет в Java, но она есть в Groovy («Java c сахаром») и Scala. Есть возможность перегрузки и в C#.
Мы не беремся утверждать, насколько хорошо или плохо перегружать операторы. Однако не вызывает сомнений, что в некоторых случаях использование этой возможности действительно необходимо. Например там, где код содержит много математических операций. Он будет выглядеть разы компактнее при использовании операторов, а не вызовов методов. А компактность, зачастую, — это больший контроль.
Закончим с теорией, и перейдем к практике.
В 10 бете редактора Realaxy ActionScript Editor (RASE) появился язык overloadedOperators. Добавить такой язык (как и любой другой) в свой проект легко — нужно лишь нажать комбинацию клавиш «ctrl+L».
Кстати, overloadelOperators RASE — это порт языка overloadedOperators из платформы MPS. Мы решили не изобретать велосипед и, изучив предметную область, пришли к выводу, что решение из MPS-платформы самодостаточно и удовлетворяет всем нашим потребностям. Однако мы добавили кое-какие «вкусности» от себя.
Мы считаем, что это правильный путь для LOP — брать лучшее из других языков и приспосабливать для своих нужд. Но об этом позже, в наших статьях о создании языковых расширений.
Создадим проект и модуль для нашего проекта. В главном классе модуля добавим код для тестирования.
В этом коде мы создали две переменные — p1 и p2 с типом Point, и хотим получить переменную p3, которая является результатом сложения двух этих точек.
Далее мы выводим на консоль значения всех переменных: p1, p2, p3. Для формирования строкового сообщения косоли мы воспользовались выражением values из языка logging.
Наш код имеет сообщение об ошибке — «Operation can’t applied to these operands». Компиляция невозможна.
Теперь создадим декларацию перегрузки операторов.
Импортируем язык overloadedOperators.
И добавляем новый рут «OverlodedOperatorsContainer». Правая кнопка на пакете и выбрать из списка.
Назовем его «MyOperators»
Внутри мы видим два блока для добавления деклараций — «overloaded binary operators» и «custom operators declarations». Устанавливаем курсор на первый блок и нажимаем ENTER. Добавлена новая декларация оператора.
Выбираем оператор «+» и назначаем тип Point для левой и правой части. Устанавливаем возвращаемое значение Point (меняем void на Point).
Теперь добавим код, который будет выполнен, если мы будем использовать оператор сложения и в правой и левой части у нас будут переменные типа Point.
И это все. Переходим в наш класс, туда, где мы написали текстовой код — и видим, что красного кода больше нет.
Запустим компиляцию. Создадим run-configuration для нашего модуля.
Если мы еще этого не сделали установим main-class.
На консоли мы видим сообщение:
Теперь сделаем более сложный пример и переопределим операции вычитания, умножения деления. Причем как на Number так и на Point.
Представим, что у нас есть задача вычислить точку, находящуюся влево-вниз на 50 пикселей от центра расстояния между двумя точками.
или еще проще:
Все очень просто. Но не будем забывать, что в реальной жизни флэшера это будет выглядеть так:
Думаем, что две предыдущие иллюстрации сами по себе являются аргументом к использованию перегруженных операторов во флэш-проектах.
Теперь научимся создавать свои операторы.
Перейдем в декларации наших операторов “MyOperators” и переместим курсор на «custom operators declarations». Добавим декларацию нажав «Enter». Укажем визуальное представление — «~=»
Наш оператор должен проверять строку на соответствие регулярному выражению.
Опишем поведение нашего оператора. Добавим новую перегрузку — обычную декларацию перегрузки, как ранее для Point, но в списке автокомплита выберем наш оператор. Левый операнд должен принимать строку, а правый должен принимать значение типа Regexp. Результатом работы нашего оператора будет Boolean. Добавим код, который выполняет наш оператор — вызов «test» у Regexp.
Создадим тестовой блок кода в классе Main.
Просто и удобно.
Чтобы не запутаться в новых операторах, на уровне редактора их использование связано с декларацией с помощью навигации. Ctrl+B или Ctrl+Click на операторе — и мы переходим в декларацию. Также можно определить, что оператор перегружен, если навести курсор на оператор и нажать Ctrl.
На Mac — Ctrl меняется на Command, конечно.
Теперь научим наш оператор новому поведению — «commutative».
Поставим курсор и выберем операцию «Flip Binary Operation». Правая и левая часть поменялась местами. В коде появилась ошибка: редактор не знает о операторе с такими операндами.
Переходим в декларацию оператора. И устанавливаем «commutative» — true.
Возвращаемся — код перестал быть красным (иногда нужно нажать F5, чтобы код обновился).
То есть наше «commutative» — это, по сути, старое доброе правило про сумму, которая не меняется при перемене мест слагаемых.
OOP гуру рекомендуют пользоваться таким поведением осторожно. Тут могут быть неожиданные эффекты. Поверим на слово и отложим себе в памяти на будущее.
Все, перегрузка операторов в ActionScript есть.
Скачать проект.