User Tools

Site Tools


at:tutorial:reflection

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Next revisionBoth sides next revision
at:tutorial:reflection [2008/09/15 17:26] – * tvcutsemat:tutorial:reflection [2008/09/15 17:39] tvcutsem
Line 29: Line 29:
  
 The code excerpt presented above uses the mirror to //introspect// on an object and uses the ''listSlots'' meta-method. The result is a table of the slots (fields and methods) provided by this object. Notice that fields are represented as a combination of an accessor and a mutator method, conforming to the Uniform Access Principle as discussed in chapter 5. Also note that the object has a field called ''super'', although this field was not explicitly defined. In AmbientTalk, ''super'' is defined implicitly for every object. The code excerpt presented above uses the mirror to //introspect// on an object and uses the ''listSlots'' meta-method. The result is a table of the slots (fields and methods) provided by this object. Notice that fields are represented as a combination of an accessor and a mutator method, conforming to the Uniform Access Principle as discussed in chapter 5. Also note that the object has a field called ''super'', although this field was not explicitly defined. In AmbientTalk, ''super'' is defined implicitly for every object.
 +
 +The code excerpt below shows how one can add and remove slots to and from an object, and how one can explicitly access values and invoke methods upon an object, reflectively:
  
 <code> <code>
->def inspectable := object: {  +// let's add a z coordinate to our point 
- def map(arg1@restArgs{ restArgs.map(arg1); } }+def [zaccessor, zmutator] := lobby.at.lang.values.createFieldSlot(`z,0)
->><obj:{super,super:=,map}+// we only add the accessor, so the slot is read-only 
->def mirrorOnInspectable := reflect: inspectable; +mirrorOnP.addSlot(zaccessor); 
->><mirror on:<obj:{super,super:=,map}>> +// let's test it: 
->mirrorOnInspectable.listFields() +p.z 
->>[<field:super>] +>> 0 
->mirrorOnInspectable.listMethods() +// we can also read slots reflectively
->>[<method:map>, <primitive method:new>,  +def x :=mirrorOnP.grabSlot(`x
-   <primitive method:init>, <primitive method:==>] +>> <accessor method for:x
->def method := mirrorOnInspectable.grabMethod(`map); +x() 
->><method:map> +>> 2 
->method.bodyExpression +// and we can also invoke methods reflectively
->>restArgs.map(arg1)+mirrorOnP.invoke(p, lobby.at.lang.values.createInvocation(`distanceToOrigin,[],[])); 
 +>> 3.605551275463989 
 +// finally, we can remove slots..
 +mirrorOnP.removeSlot(`z);
 </code> </code>
  
-Using a mirror on an object, it is possible to get access to a representation of the object's methods and fields, allowing the programmer to read the value of a field, or as is exemplified above inspect the body of a method. This type of reflection is quite useful to for instance construct an inspector for live AmbientTalk objects.  +The following example contains the core of a unit testing framework by showing how to select all zero-argument methods of an object whose name starts with ''test'' and invoke them.
- +
-In addition to allowing a program to reason about the structure of its objects, mirrors can also be used to perform operations such as method invocation in a first-class manner. The following example shows how to select all zero-argument methods whose name starts with ''test'' and invoke them.+
  
 <code> <code>
 >def isTestMethod(meth) { >def isTestMethod(meth) {
    (meth.name.text ~= "test.*").and:    (meth.name.text ~= "test.*").and:
-   { meth.parameters == [] } };+   { meth.parameters.length == } };
 >><closure:isTestMethod> >><closure:isTestMethod>
 >def retainTestMethods(obj) { >def retainTestMethods(obj) {
Line 62: Line 65:
 >def runTest(obj) { >def runTest(obj) {
    retainTestMethods(obj).each: { | meth |     retainTestMethods(obj).each: { | meth | 
-     (reflect: obj).invoke(obj, `(.#(meth.name)())) } };+     (reflect: obj).invoke(obj, lobby.at.lang.values.createInvocation(meth.name, [], [])) } };
 >><closure:runTest> >><closure:runTest>
 >runTest(object: {def testOne() { system.println(`ok) } }); >runTest(object: {def testOne() { system.println(`ok) } });
Line 69: Line 72:
 </code> </code>
  
-This part of the tutorial has provided a basic feeling of how AmbientTalk's default mirrors can be created and the kind of power they offer. The default mirrors offer a much wider range of capabilities than those presented in this section, however. A complete overview of all meta-operations will be presented in the final chapter of this tutorial.+This part of the tutorial has provided a basic feeling of how AmbientTalk's default mirrors can be created and the kind of power they offer. The default mirrors offer a much wider range of capabilities than those presented in this section, however. To get a complete overview, try to inspect AmbientTalk's prototypical mirror, named ''defaultMirror'', e.g. by using introspection: 
 + 
 +<code> 
 +defaultMirror.listSlots.map: { |slot| slot.name } 
 +</code> 
 + 
 + 
 +A complete overview of all meta-operations will be presented near the end of this chapter.
  
 ===== Mirages ===== ===== Mirages =====
at/tutorial/reflection.txt · Last modified: 2010/11/16 16:32 by tvcutsem