Вот результаты моего собственного углубленного исследования:
Расширение класса Class, по сути, невозможно, хотя это нигде не документировано, что я еще не видел. Из моего исследования я теперь убежден, что сам класс Class не включает в себя все качества, которыми обладают другие классы верхнего уровня, хотя все они, как говорят, выходят из класса Object.
Еще одним разочарованием является тот факт, что создание подклассов различных классов верхнего уровня приведет к нескольким различным сообщениям об ошибках, что затруднит определение проблем. Начнем с простого примера: если вы попытаетесь создать подкласс многих примитивных типов данных ActionScript (int, uint, Number, String, Boolean и т. Д.), Вы получите следующую ошибку compiler :
1016: Base class is final.
Это имеет смысл, потому что просмотр документов для любого из этих классов показывает, что они действительно окончательные:
Package Top Level
Class public final class Boolean
Inheritance Boolean -> Object
Последнее слово, конечно, означает, что другой класс не может расширять класс, помеченный как final . Теперь для более сложного примера, давайте посмотрим на расширение класса Function. Класс Function не является окончательным, согласно документам. Поскольку это не является окончательным, означает ли это, что мы можем расширить класс Function для создания наших собственных специализированных функциональных объектов? Вот определение:
class MyFunction extends Function { /*...*/ }
.. а затем в время выполнения :
VerifyError: Error #1103: Class ::MyFunction cannot extend final base class.
Сравните это с ошибкой примитивного типа данных выше. Эта ошибка произошла во время компиляции, поскольку унаследованный примитивный класс был фактически помечен как финальный. Класс Function не помечен как финальный, но класс продолжает вести себя так, как если бы он был, только во время выполнения.
Теперь мы подошли к основной проблеме: расширению класса Class. Как и в случае с классом Function, класс Class не является окончательным. Кроме того, класс Class является динамическим, то есть новые свойства могут быть добавлены к объекту Class во время выполнения.
В качестве интересного дополнения: класс Function также является динамическим, и я полагаю, что эта часть обеспечивает постоянную поддержку старых механизмов наследования прототипов, присутствующих в диалекте ECMAscript. На этом диалекте функции используются как своего рода классы (ну, в общем, прототипы), а способность функций добавлять свойства во время выполнения является частью возможности наследования прототипов.
Теперь, насколько я понимаю, свойства объекта Class такие же, как статические свойства, доступные для любого экземпляра этого класса. Таким образом, должно иметь логический смысл, что кто-то может захотеть манипулировать объектом Class во время выполнения, позволяя ему изменить поведение этого класса и его экземпляров. То, что класс Class является динамическим, усиливает это представление.
Поскольку класс Class не является окончательным, мне было любопытно посмотреть, можно ли расширить класс Class, создать собственную специализацию модели Class и работать где-нибудь в области метаязыка. Я оставлю на следующий день обсуждение того, почему кто-то хотел бы сделать это, и какую власть это предположительно допустило бы. Теперь для заключительного примера, давайте расширим класс Class. Вот определение:
// the definition causes no errors on its own, even though the compiler "sees" it
class MyClass extends Class { /*...*/ }
/* elsewhere */
MyClass; // the only mention of MyClass beyond the definition
.. а затем в время выполнения :
verify global$init()
stack:
scope:
locals: global
/* snip about 120 lines */
46:getlex 34
stack: global Class$?
scope: global Object$ Class$
locals: global
48:newclass MyClass$cinit()
VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.
at global$init()
Святая трассировка стека! VerifyError
зарезервировано для искаженных данных SWF. Исходя из того, что я мог найти, это также, как «ошибка» во Flash Player имеет тенденцию проявляться. В любом случае это немного выходит за рамки обычной ошибки ActionScript.
На данный момент довольно трудно понять, что именно происходит, но это то, что я смог до сих пор сделать вывод.
VerifyError: Error #1107: The ABC data is corrupt, attempt to read out of bounds.
Я (ошибочно, см. Ниже комментарий) считаю, что «ABC» обозначает Абстрактный базовый класс, который является термином, применяемым к классам, которые не могут быть созданы, только расширены. Однако вышеуказанная ужасающая ошибка возникает не в момент создания, а при первом доступе к подклассу класса MyClass. Фактически, в коде примера я никогда не создаю экземпляр объекта MyClass, я ссылаюсь только на сам класс MyClass.
Я провел еще несколько тестов и обнаружил, что объекты Class, по-видимому, не имеют конструкторов, по крайней мере, того типа, который обычно происходит из подклассов Object. Просто набрав new Class();
в любом месте вашего кода, это наглядно продемонстрирует этот факт, но вы можете исследовать это далее, проверив свойство .constructor
и другие приемы. В результате этого экземпляры класса Class в лучшем случае являются объектами второго класса, поскольку они не могут быть созданы во время выполнения.
Сначала я подозревал, что это была точная причина моего противного VerifyError
. Однако теперь я считаю, что существует много других элементов класса, невидимых для нашего собственного кода ActionScript, которые могут существовать или не существовать в классе Class, классе Function или других любопытных местах. Конечно, когда Flash Player пытается получить доступ к одному из необходимых для расширения базового класса, и он не существует (поскольку Class, возможно, является ABC, поэтому отсутствуют некоторые элементы, присутствующие в обычном классе), можно ожидать увидеть за пределами VerifyError
.
Таким образом, расширение класса теперь выглядит невозможным. Может показаться, что класс Class не включает в себя все качества, которые большинство других классов верхнего уровня наследуют от Object, хотя это сложно проверить.
Я бы предпочел видеть более конкретное сообщение об ошибке в результате расширения класса, но в данный момент такой вещи нет. Мне бы хотелось, чтобы некоторые возможности метапрограммирования вернулись к ActionScript. Пока достаточно знать, что это невозможно сделать, по крайней мере, таким образом.