При выполнении метапрограммирования методы метаобъекта вызываются во время компиляции, так как объявления анализируются.Поэтому метод compose
вызывается сразу после разбора объявления myclass foo { }
.Затем результаты компиляции модуля сохраняются, и при загрузке модуля ничего в метаобъекте не будет снова обрабатываться.
Нет поддерживаемого способа, которым я знаю, для внедрения обратного вызова во время загрузкив модуль, где тип объявляется.Тем не менее, можно установить символы в отдельный пакет - используемый в качестве реестра - и затем найти их там.
Например, если у меня есть lib/MyClass.pm6
, который выглядит следующим образом:
package MyRegistry { }
class MyParentClass { }
class MyHOW is Metamodel::ClassHOW {
method compose ( Mu \type ) {
MyRegistry::{self.name(type)} = type;
self.add_parent( type, MyParentClass );
callsame;
}
}
my package EXPORTHOW {
package DECLARE {
constant myclass = MyHOW;
}
}
И я пишу некоторые файлы mods/A.pm6
и mods/B.pm6
, например:
use MyClass;
myclass A { }
И это:
use MyClass;
myclass B { }
Затем, когда я требую их в сценарии, подобном этомуи выгрузите ключи в MyRegistry
, они оба будут зарегистрированы там:
use MyClass;
for dir('mods', test => /pm6$/) {
require $_;
}
dd MyRegistry.WHO.values;
Таким образом, вы получите предсказуемый способ найти их все.
Обратите внимание, что для такой техникичтобы работать, вам действительно нужно хранить их в Stash
, так как загрузчик знает, как их объединить по символам, тогда как другие типы, по-разному затронутые во время компиляции разных модулей, приведут к конфликтам времени загрузки.
Перед вами стоит небольшая задача - убедиться, что все установлено под достаточно уникальным ключом;имя типа, которое я использовал здесь, вероятно, не достаточно уникально в общем.Возможно, я бы просто сгенерировал что-то достаточно случайное, чтобы вероятность столкновения была крайне маловероятной.