Как создать класс, который не наследуется ни от какого другого класса? - PullRequest
0 голосов
/ 25 июня 2018

Если вы создаете класс:

class Foo { }

, класс унаследует все свои методы от Any, а затем Mu.

Я хочу создать класс, которыйне наследуется ни от какого другого класса: он должен содержать один FALLBACK метод, который должен перехватывать все вызовы методов для экземпляров этого объекта.

Я просматривал MetaModel код, но, кажется, нет простого способа достичь этой цели.Все предложения приветствуются!

ОБНОВЛЕНИЕ : Я решил пойти перехватить любой вызов метода , как описано Джонатаном Уортингтоном.Это привело к появлению двух новых модулей Perl 6 на CPAN: InterceptAllMethods и Object :: Trampoline .

Ответы [ 2 ]

0 голосов
/ 26 июня 2018

Вот еще одна идея: вы можете создать новый метакласс, который наследует от ClassHOW, но переопределяет методы, которые роль Perl6::Metamodel::MROBasedMethodDispatch предоставляет версиями, которые пропускают все родительские классы.

Например, это:

# Maybe this belongs on a role. Also, may be worth memoizing.
method can($obj, $name) {
    my @meths;
    my %smt := self.submethod_table($obj);
    if nqp::existskey(%smt, $name) {
        @meths.push(%smt{$name});
    }
    for self.mro($obj) {
        my %mt := $_.HOW.method_table($_);
        if nqp::existskey(%mt, $name) {
            @meths.push(%mt{$name})
        }
    }
    @meths
}

станет

method can($obj, $name) {
    my @meths;
    my %smt := self.submethod_table($obj);
    if nqp::existskey(%smt, $name) {
        @meths.push(%smt{$name});
    }
    @meths
}

Таким образом, вы не столкнетесь с проблемами с кодом, который ожидает, что все типы будут соответствовать Mu, но вы все равно можете избежать случайного вызоваметоды из Mu.

0 голосов
/ 26 июня 2018

Это возможно, хотя вы, вероятно, столкнетесь с практическими проблемами, которые потребуют дополнительных усилий.Вызов логики построения - хороший пример, уже упомянутый в комментарии.Кроме того, ожидается, что все успешно проверит проверку типа Mu;такие проверки в большинстве мест исключаются как оптимизация, но не в других, и поэтому вы можете столкнуться с различными ошибками проверки типов.

Помимо этого, вот как это сделать.Во-первых, создайте модуль, который экспортирует новый мета-тип для class.

class RootHOW is Metamodel::ClassHOW {
    method has_default_parent_type(|) { False }
}
package EXPORTHOW {
    constant class = RootHOW;
}

. Метамодель должна каким-то образом использоваться для установки типа Mu, и поэтому здесь мы(ab) использовать механизм, который обычно означает «нет, родительский тип по умолчанию еще не существует, потому что мы до сих пор не загрузили нашу объектную модель».Вставьте это в модуль, скажем, под названием Parentless, и тогда можно сделать это:

use Parentless;
class NotAMu {
    method FALLBACK($name, |c) {
        say "called $name with {c.perl}"
    }
}
NotAMu.new

, который выдает:

called new with \()

Если ваша цель просто перехватить каждый метод отправки, есть гораздо менее разрушительный способ, который не портит систему типов.На данный момент ему нужен собственный метакласс, который отключает публикацию кэша методов:

class InterceptHOW is Metamodel::ClassHOW {
    method publish_method_cache(|) { }
}
package EXPORTHOW {
    constant class = InterceptHOW;
}

Затем вы можете написать:

use InterceptAllTheMethods;
class InterceptThemAll {
    method ^find_method(Mu $obj, Str $name) {
        return -> | { say "calling $name" }
    }
}
InterceptThemAll.new

Обратите внимание, что в отличие от FALLBACK, здесь вы возвращаете объект кодатогда он будет вызван.Вы также можете написать эту find_method реализацию в метаклассе, что может быть лучшим факторингом;Трудно сказать, не зная проблемы под рукой.

Этот подход не вызовет проблем, связанных с проверкой типов, позволит вам перехватывать каждую диспетчеризацию метода, и достаточно просто искать такие вещи, как bless и просто делегироватьте для Mu реализации.

...