| |||
![]()
|
![]() ![]() |
![]()
Симуляция жабьими средствами множественного наследования и передачи параметров по ссылке Выпало компилять в Жабу язычок с множественным наследованием, передачей пароаметров по ссылке и значению, сборкой мусора и обильными библиотеками. Открыто настоящим именем называть язычок не велят, видимо, чтобы не пришел, да и какая разница. Жаба - не очень-то подходящий целевой язык. С одной стороны, все возможности исходного языка прямо ее средствами не выражаются. С другой, низкоуровневый машинно-независимый ассемблер из нее тоже не ахти - адресов и смещений почти нет, равно как и контроля за размещением в памяти. 1. Каким путем мы не пойдем Можно было бы, конечно, 2. Товарищи по ссылке В Жабе у локалов адресов нет, смещений нет, и запись активации не объект. Соответственно, простыми средствами передачу параметров по ссылке не организовать. При этом семантика передачи параметров по значению в язычке в целом соответствует жабьей - есть элементарные типы, которые копируются, и объекты, которые нет. Элементарыне типы тоже примерно одинаковые. Для скорости и пущей розрачности хочется передачу параметра по значению оставить передачей по значению и мучаться лишь с передачей по ссылке. Поступаем так. Для каждого элементарного типа исходного язычка type и бестипового указателя на объект заводим жабий класс Variable$typeдля хранения переменной этого типа. В классе описываем аксессоры и все необходимые операции над переменной соответствующего типа. Далее, если точно известно, что переменная исходного языка нигде не передается по ссылке, транслируем ее непосредственно в элементарный жабий тип. Собственно, такая уверенность есть только по отношению к локалам и приватным полям финальных классов. Во всех прочих случаях переменную транслируем в объект класса Variable$type. При передаче переменной по ссылке передаем адрес этого объекта. При передаче по значению извлекаем значение из объекта и передаем его. Ужас, да. Но не ужас-ужас-ужас. Ужас и моральный террор впереди. 3. Множественное наследование В жабе есть множественное наследование среди интерфейсов. Среди классов его нет. Нет возможности вставить один объект внутрь другого. По непонятной причине в интерфейсах нельзя писать кода. Чуть более понятно, почему в них нельзя писать деклараций полей. Кряхтя и плюясь, поступаем так. Отделяем тип от представления. Тип моделируем жабьим интерфейсом. В для публичных переменных в интерфейс принудительно добавляем аксессоры к полям, представленными объектами-переменными Variable$type. Представление моделируем классом без наследования. Наследованные поля вручную копируем из представлений надклассов язычка, переименовывая по необходимости (привет процессу сочленения из Симулы-67). Осталось организовать наследование методов. Для связывания с интерфейсом метод должен быть виртуальным. Однако ж наследования на уровне представлений нет, поэтому, чтобы избежать копирования тела, тело заключаем в статическую функцию.По мере необходимости добавляем явный параметр для объекта-получателя this/self и параметры для всех используемых полей, чтобы отвязать значения от мест их хранения. Вот, собственно, и все. Теперь страшный пример для зануд, дочитавших до этого места. Исходный текст на язычке (синтаксис изменен): class A { public: int a; int& get_ref_a() { return &a; } int get_a() { return a; } void f() { get_ref_a()++; } }; class B { private: int b; public: int& get_ref_b() { return &b; } }; class C: A, B { private: int c; public: int& get_ref_a() { return get_ref_b(); } int h() { return A::a + get_ref_a() + c; } }; Результат трансляции (подлежит улучшению путем выбрасывания лишнего): interface Type$A { public: Variable$int a(); Variable$int get_ref_a(); int get_a(); void f(); }; class Representation$A implements Type$A { private: Variable$int var$a; public: Variable$int a() { return var$a; } // Тело метода для ссылки при наследовании // Все используемые поля передаются параметрами static Variable$int get_ref_a(Variable$int a) { return var$a; } // Связывание с интерфейсом Variable$int get_ref_a() { return get_ref_a(var$a); } // Тело метода для ссылки при наследовании // Все используемые поля передаются параметрами static int get_a(int a) { return a; } // Связывание с интерфейсом int get_a() { return get_a(var$a.get()); } // Тело метода для ссылки при наследовании // Все используемые поля передаются параметрами // Причем именно Type, а не Representation static void f(Type$A self) { return self.get_ref_a().inc(); } // Связывание с интерфейсом void f() { f(this); } }; interface Type$B { public: Variable$int get_ref_b(); }; class Representation$B implements Type$B { private: Variable$int var$b; public: static Variable$int get_ref_b(Variable$int b) { return b; } // Связывание с интерфейсом Variable$int get_ref_b() { return get_ref_b(b); } }; interface Type$С extends Type$A, Type$B { private: int c; public: int h(); }; class Representation$C implements Type$C { private: Variable$int var$A$a; Variable$int var$B$b; Variable$int var$c; public: // Привязываем наследованное статическое тело к полям Variable$int a() { return Representation$A.a(var$A$a); } // Тело метода для ссылки при наследовании // Все используемые поля передаются параметрами static Variable$int get_ref_a(Variable$int b) { return Representation$B::get_ref_b(b); } // Наследованный метод перекрыт Variable$int get_ref_a() { return get_ref_a(var$B$b); } // Привязываем наследованное статическое тело к полям int get_a() { return Representation$A.get_a(var$A$a.get()); } // Привязываем наследованное статическое тело к полям void f() { Representation$A.f(this); } // Привязываем наследованное статическое тело к полям Variable$int get_ref_b() { return Representation$B.get_ref_b(var$B$b); } // Тело метода для ссылки при наследовании // Все используемые поля передаются параметрами static int h( Type$С self, int a, int с ) { return a + self.get_ref_a() + c; } // Связывание с интерфейсом int h() { return h( this, A$a.get(), c.get() ); } }; По-моему, выглядит жутко и работать быстро не будет, зато сборщик мусора достался на халяву и библиотеки легко попользовать - реализация может наследовать из соответствующего жабьего объекта или реализовать дополнительные жабьи интерфейсы. |
||||||||||||||
![]() |
![]() |