@@ -2528,15 +2528,63 @@ When the parser encounters a package declarator, it uses the name of
2528
2528
the declarator (such as C<class> or C<grammar>) to look up the type of
2529
2529
meta-object to use. The default meta-objects support the standard Perl 6
2530
2530
OO semantics. However, it is possible for a module to export different
2531
- meta-objects with different semantics. This is done by making entries in
2532
- an EXPORTHOW package, which in turn must be located in UNIT of the module.
2533
- The name it is installed under maps to a package or type declarator name.
2534
-
2535
- Thus, a module can provide a replacement implementation of the meta-object
2536
- type used for grammars like this:
2531
+ meta-objects with different semantics. This is done by declaring an
2532
+ C<EXPORTHOW> package, which should be located in C<UNIT> of the module
2533
+ (and thus can be lexically scoped).
2534
+
2535
+ Just as the C<EXPORT> package never contains symbols directly, but instead
2536
+ contains packages that denote tags and directives (such as C<DEFAULT>), the
2537
+ C<EXPORTHOW> package expects meta-objects to be installed under one of the
2538
+ following packages:
2539
+
2540
+ SUPERSEDE Uses the exported meta-object for the named declarator in
2541
+ the scope that the module is imported in to
2542
+ COMPOSE Takes the meta-object currently in effect for the named
2543
+ declarator and composes the exported role into it
2544
+ DECLARE Like SUPERSEDE, but also adds a new package declarator to
2545
+ the grammar if required
2546
+
2547
+ For example, a module can replace the meta-object used for the C<grammar>
2548
+ keyword in any scope it is imported into by doing:
2549
+
2550
+ my module EXPORTHOW::SUPERSEDE { }
2551
+ EXPORTHOW::SUPERSEDE<grammar> = TracedGrammarHOW;
2552
+
2553
+ An MVC framework could declare a new C<controller> package declarator and
2554
+ associate it with a meta-class of its choosing by doing:
2555
+
2556
+ my module EXPORTHOW::DECLARE { }
2557
+ EXPORTHOW::DECLARE<controller> = ControllerHOW;
2558
+
2559
+ The C<COMPOSE> directive is perhaps the most sophisticated, and its usage is
2560
+ encouraged where possible. Instead of exporting an entirely new meta-object,
2561
+ C<COMPOSE> enables exporting a role. At the point the declarator is first used,
2562
+ all roles exported for it through C<COMPOSE> will be taken together and added
2563
+ to a class derived from the current meta-object for the declarator (which may
2564
+ have been provided by a SUPERSEDE or DECLARE export from another module used in
2565
+ the scope). This class will then be composed, with any conflicts indicated.
2566
+
2567
+ my module EXPORTHOW::COMPOSE {
2568
+ # Provide a role that adds logging to class method calls.
2569
+ role class {
2570
+ method find_method($obj, $name) {
2571
+ say "Calling $name";
2572
+ nextsame;
2573
+ }
2574
+
2575
+ method publish_method_cache($obj) {
2576
+ # Make sure all dispatches go through find_method
2577
+ }
2578
+ }
2579
+ }
2537
2580
2538
- my module EXPORTHOW { }
2539
- EXPORTHOW::<grammar> = TracedGrammarHOW;
2581
+ The benefit of C<COMPOSE> is that it enables two modules that extend a meta-object
2582
+ in a non-conflicting way to be used together in the same scope, with explicit
2583
+ detection of conflicts if they occur. For example, if one module wishes to
2584
+ override C<compose> and another wishes to override C<find_method>, the two can
2585
+ be used together safely. By contrast, C<SUPERSEDE> and C<DECLARE> can only be used
2586
+ by one module per declarator in a given scope, thwarting composition. The
2587
+ compiler should produce an error if this rule is broken.
2540
2588
2541
2589
The easiest way to define a new meta-object is to inherit from an existing
2542
2590
meta-object.
0 commit comments