Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 367 lines (267 sloc) 13.37 kb
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
1 =head1 The Rakudo Metamodel
2
3
4 =head2 Warning
5
6 What follows is the current way this works in Rakudo. Parts of it may one day
7 become spec, other bits likely never will. All of it is liable to change as we
8 work out what should be spec and what shouldn't be, and also co-ordinate with
9 other implementations and interested parties to make sure those bits that we
10 determine should be specification are spec'd in a way that matches our shared
11 desires and needs, so far as that's possible. It goes without saying that in
12 doing the things described in this document, you're walking barefoot through a
13 construction site. For now, tread carefully, and be prepared to patch up in
14 response to changes.
15
16
17 =head2 Overview
18
19 Meta-objects are simply objects that describe parts of the object model. The
20 metamodel lays down the interface that these objects should provide. In Rakudo
21 we have several types of meta-object, all of which have an associated API
22 (sometimes known as a Meta-object Protocol, just to make sure the whole topic
23 appears to be sufficiently scary to outsiders, or something). This document
24 defines the API for:
25
26 =over 4
27
28 =item Packages meta-objects (representing classes, grammars, roles, etc);
29 ones included in Rakudo include ClassHOW, GrammarHOW and RoleHOW.
30
31 =item Attribute meta-objects (representing attributes); the default one of
32 these is simply called Attribute.
33
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
34 =item Composition meta-objects (e.g. specifying role composition algorithms)
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
35
36 =back
37
38 The composition model warrants a little explanation, since it is broken into
39 a couple of parts. We'll stick with classes and roles for now, but we define
40 the interface in the expectation that one day we might want to have things
41 that are composed into a class following some composition algorithm that may
42 be given a different name. Thus we talk in terms of "composables".
43
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
44 There are two important things. First, the actual composer - implementing the
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
45 composition algorithm - is not a part of the thing we're composing or the
46 thing we're composing into (that is, it is independent of the class and the
47 role). Second, it is up to the thing being composed (e.g. the role in the case
48 of composing a role into a class) to supply the composer.
49
50
51 =head2 Package meta-object API (aka HOW API)
52
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
53 This is the API for packages. When we compile something like:
54
55 class Town is Place {
56 method bar() { say "mmm beer" }
57 }
58
59 Then it results in a set of calls like:
60
61 my $temp = ClassHOW.new('Town');
62 &trait_mod:<is>($temp, Place);
63 $temp.^add_method('bar', anon method bar() { say "mmm beer" });
64 ::Town := $temp.^compose();
65
66 Most of these are calls on the meta-class to methods that give meaning to the
67 keywords the user wrote in their code. The following methods are supported as
68 a minimum.
69
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
70
71 =over 4
72
73 =item method new($name?)
74
eacccf9 Carl Mäsak [docs/metamodel.pod] fixed small typo
masak authored
75 Creates something that knows how to provide its metaclass, e.g. through the
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
76 same mechanism as C<.HOW> obtains it. It need not be the final type-object that
77 may be installed in a namespace or lexpad - that is for compose to return. However,
78 there's nothing to stop it being.
79
80 Whether a new instance of the meta-class is created or not is totally up to the
81 implementation of the C<new> method. For the standard Perl 6 C<class> keyword in
82 Rakudo, we create an instance of the meta-class and a temporary object that only
83 knows how to reference the meta-class instance. However, if you were doing a more
84 prototype-OO implementation, then you could instead have the meta-class be a
85 singleton and return a new object, and the object itself knows completely about
86 its methods, attributes and so forth, rather than this knowledge belonging to the
87 meta-class.
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
88
89 =item add_method($meta, $name, &code_ref)
90
91 Adds a method to the methods table of C<$meta> under the given C<$name> and with
92 the given implementation.
93
94 =item add_attribute($meta, $name)
95
96 Adds an attribute of the given C<$name> to C<$meta>.
97
98 =item add_parent($meta, $parent)
99
100 Adds the given parent to C<$meta>.
101
102 =item add_composable($meta, $composee)
103
104 Takes something that we are able to compose (for example, a role) and adds it
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
105 to the composition list. Certainly, none of the built-in implementations of
106 add_composable immediately perform any composition at this point. Instead,
107 they add the composable to a "to do" list, and at the point we call "compose"
108 to finish the composition of the package, and the application of all the
109 composables takes place. You probably want to do something similar.
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
110
111 =item applier_for($meta, $target)
112
113 For non-composables (that is, packages that cannot be composed into others),
114 this is an error. Otherwise, it returns something that we can use to apply
115 the current package to the target. The thing returned should implement the
116 composer API. It may be convenient to implement this is a set of multi subs.
117
118 =item compose($meta)
119
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
120 Finalizes the creation of the package. It can do any other composition-time
121 operations, such as role composition and calling the composition hook on all
af3d38d Martin Berends [docs/metamodel.pod] minor typo and layout corrections
mberends authored
122 attributes added to the package. Returns the type object that we're going to
123 actually install into the namespace or lexical pad, or just return if it's
124 an anonymous declaration.
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
125
126 =back
127
128 This is the declarational part of the API, however the introspection part
129 should also be implemented. Please see the Introspection section of S12 for
130 details on this.
131
132
133 =head2 Attribute meta-object API
134
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
135 This is the API that objects representing attributes should expose. The
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
136 attribute meta-object is responsible for generating any accessor and/or
137 delegation methods associated with the attribute.
138
139 =over 4
140
48b90ee Jonathan Worthington Tweak to attribute meta-object API.
jnthn authored
141 =item new($name, :$has-accessor, :$rw, :$handles, :$build, :$type)
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
142
143 Creates a new attribute meta-object, initialized with the name, whether or
144 not the attribute has an accessor, whether or not that accessor 'is rw' and -
145 if there was a handles trait modifier on the attribute - the handles trait
146 modifier.
147
48b90ee Jonathan Worthington Tweak to attribute meta-object API.
jnthn authored
148 =item compose($meta-package)
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
149
150 Takes the attribute and does any final composition tasks (such as installing
48b90ee Jonathan Worthington Tweak to attribute meta-object API.
jnthn authored
151 any accessor methods and/or delegators). The parameter is the meta-object of
152 the package that the attribute belongs to; you can call .add_method on it to
153 add methods, for example.
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
154
155 =back
156
157
158 =head2 Composer meta-object API
159
160 The composer is responsible for composing something composable (in standard
161 Perl 6, that's a role) into some other object (perhaps a class or another
162 role or an instance). The minimal interface need only support one method,
163 but it may well be that a composee and a composer choose to share knowledge
164 of more than this (for example, a "requires" or "conflicts" list).
165
166 =over 4
167
168 =item apply($target, @composees)
169
170 Applies all of the composees to the target, or throws an exception if there
171 is a problem with doing so. It's totally up to the composer exactly what it
172 does; the default composer for Perl 6 roles will construct a single
173 intermediate role and then compose that into the target, for example. Since
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
174 the model is intended for more general composition-y things rather than just
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
175 roles as are commonly defined today, we choose to give the composer a view of
176 all of the composees.
177
178 =back
179
180
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
181 =head2 Metaclass Compatibility
182
183 Warning: Conjectural.
184
185 One rather complex issue we run into is what happens if you want to inherit
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
186 from something that has a different metaclass. For now, we require that if
187 some class S isa T, then also S.HOW isa T.HOW. This means that all other types
188 of class-ish things that want to have a custom metaclass should subclass
189 ClassHOW (either directly or transitively). Thus, this is fine:
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
190
191 class A { }
192 thingy B is A { }
193 otherthingy C is B { }
194
195 If the following is true:
196
197 OtherThingyHOW.isa(ThingyHOW) and ThingyHOW.isa(ClassHOW)
198
199
200 =head2 Composer Compatibility
201
202 Warning: Conjectural.
203
204 TODO: Provide a solution to the problems described here.
205
206 Given it's the things we compose that determine what composer to use, we may
207 easily run into a situation where different things want a different composer.
208 At some level that's OK - if we want to support a more general notion of
209 "things that do something composition-ish" then it is probably too restrictive
210 to just always make this an error in the long run. For now, however, we do
211 just that; when we have a good solution, we can relax the restriction.
212
213 We do have the nicety that once we hit runtime, since composition is flattening
af3d38d Martin Berends [docs/metamodel.pod] minor typo and layout corrections
mberends authored
214 by nature, we don't have any relationship at runtime with something that was
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
215 composed in (besides keeping it in our list of "things that we composed"). Thus
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
216 the problem of the behaviors of two different appliers is only
af3d38d Martin Berends [docs/metamodel.pod] minor typo and layout corrections
mberends authored
217 a composition-time issue and not a runtime one.
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
218
219
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
220 =head2 Associating a package declarator with a metaclass
221
222 Rakudo provides two levels of hookage for creating new types of package
223 declarator. You will very likely only need this one, which is the HOW map,
224 %*HOW. This is simply a hash that maps the name of a scope declarator to the
225 name of the HOW to create. At the entry point to your derived grammar, you
0b83903 Bruce Gray Fixed various typos in comments and error messages.
Util authored
226 should temporize the current HOW hash from the calling language, and add
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
227 mappings from names of package declarators that you will introduce to the HOW
228 to use. By default, this hash contains things like:
229
230 { class => 'ClassHOW', role => 'RoleHOW' }
231
232 It's completely fine for multiple package declarators to map to the same HOW
233 - you may just wish to introduce a new one as better documentation but not
234 need to do anything more special in terms of the meta-model. Note that your
235 rule for parsing the scope declarator sets the name of the thing in this map
236 in the $*PKGDECL global. For example, here is one from STD.
237
238 token package_declarator:role {
239 :my $*PKGDECL ::= 'role';
240 <sym> <package_def>
241 }
242
243 You should do the same (and it's probably nice if what you set matches the
244 name of the symbol you parse).
245
246
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
247 =head2 Meta-programming Example: Adding AOP Support
248
249 Note that this currently does not work in Rakudo, and will probably change a
250 bit. It's purpose is mostly a thought experiment to try and help sanify the
251 design of the metamodel.
252
253 slang AOP {
254 method TOP {
255 temp %*HOW;
256 %*HOW<aspect> := AspectHOW;
257 my $lang = self.cursor_fresh( AOP );
258 $lang.comp_unit;
259 }
260 token package_declarator:sym<aspect> {
261 :my $*PKGDECL := 'aspect';
262 <sym> <package_def>
263 }
264 }
265
266 class AspectComposer {
267 method apply($target, @aspects) {
268 my @wrappables = $target.methods(:local);
269 for @aspects -> $aspect {
270 for $aspect.method_wrappers.kv -> $name, $wrapper {
271 my ($wrappee) = @wrappables.grep({ .name eq $name });
272 if $wrappee {
273 $wrappee.wrap($wrapper);
274 }
275 else {
276 die "No sub found to wrap named '$name'";
277 }
278 }
279 }
280 }
281 }
282
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
283 class Aspect {
284 has $.HOW;
285 has $.Str;
286 method WHAT() { self }
287 method defined() { False }
288 }
289
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
290 class AspectHOW {
291 has %.method_wrappers;
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
292
293 method new($name) {
294 return Aspect.new(
295 HOW => self.bless(*),
badc61d Moritz Lenz [docs] perl5o found by ash_++
moritz authored
296 Str => $name ~ "()"
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
297 );
298 }
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
299
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
300 method add_method($obj, $name, $method) {
301 $.method_wrappers{$name} = $method;
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
302 }
303
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
304 multi method composer_for($obj, $ where { .can('methods') }) {
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
305 return AspectComposer;
306 }
307
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
308 multi method composer_for($obj, Object) {
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
309 die "Can only apply aspects to things that expose methods";
310 }
311
5e7ac5a Jonathan Worthington Re-visit the Rakudo meta-model spec and try and be less wrong, though we...
jnthn authored
312 method compose($obj) {
313 return $obj;
8117a01 Jonathan Worthington More meta-ponderings.
jnthn authored
314 }
315
316 method add_attribute($meta, $attr) {
317 die "Aspects do not support attributes";
318 }
319
320 method add_parent($meta, $parent) {
321 die "Aspects do not support inheritance";
322 }
323
324 method add_composable($meta, $composable) {
325 die "Aspects do not support being composed into";
326 }
327 }
328
329 This could then we used as something like:
330
331 use AOP;
332
333 aspect LogToStderrToo {
334 method log($message) {
335 $*ERR.say($message);
336 nextsame;
337 }
338 }
339
340 class ErrorLog does LogToStderrToo {
341 method log($message) {
342 my $fh = open("log", :a);
343 $fh.say($message);
344 $fh.close;
345 }
346 }
347
348 Note that a usable implementation would want a bit more than this, and have
349 many other design considerations.
350
351
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
352 =head2 Influencing package code generation
353
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
354 Note: This is highly Rakudo-specific and very likely to remain that way.
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
355 The good news is that you won't need to do it often.
356
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
357 Rakudo has a compile-time representation of the package currently being
358 compiled. This is the thing that ends up actually generating
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
359 the code - PAST nodes - that make the calls on the metaclass. By default, we
360 always create an instance of Perl6::Compiler::Package, apart from for roles
361 and modules, for which we need to do some slightly different code generation
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
362 - those use a subclass of it, such as Perl6::Compiler::Role. You may modify
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
363 %*PKGCOMPILER, again keying on $*PKGDECL, to specify something other than the
bf746af Carl Mäsak [docs/metamodel.pod] rw review
masak authored
364 default. You should then write a subclass of an existing handler for this and
7921dad Jonathan Worthington Fill out metamodel details somewhat. No doubt this will need and get twe...
jnthn authored
365 implement the same interface (plus any other bits you'll need - it's just a
366 class).
Something went wrong with that request. Please try again.