Difference between revisions of "Guide:Introspection and Reflection"

From IokeWiki
Jump to: navigation, search
(Introspection and reflection)
Line 8: Line 8:
 
: Should be a text that gives the full name of the kind this object is closest mimic to. Except for nil, true and false, this will return a text that starts with a capital letter.
 
: Should be a text that gives the full name of the kind this object is closest mimic to. Except for nil, true and false, this will return a text that starts with a capital letter.
  
<pre>Foo = Origin mimic
+
<source lang="ioke">Foo = Origin mimic
 
Foo mimic kind println
 
Foo mimic kind println
  
 
Foo Bar = Origin mimic
 
Foo Bar = Origin mimic
Foo Bar mimic kind println</pre>
+
Foo Bar mimic kind println</source>
 
This code will first print &quot;Foo&quot;, and then print &quot;Foo Bar&quot;, since an object assigned to a cell with a capital initial letter will get a new kind value.
 
This code will first print &quot;Foo&quot;, and then print &quot;Foo Bar&quot;, since an object assigned to a cell with a capital initial letter will get a new kind value.
  
Line 18: Line 18:
 
: Takes one text argument and returns true if the object has that kind anywhere in its mimic chain.
 
: Takes one text argument and returns true if the object has that kind anywhere in its mimic chain.
  
<pre>Foo = Origin mimic
+
<source lang="ioke">Foo = Origin mimic
 
foo = Foo mimic
 
foo = Foo mimic
foo kind?(&quot;foo&quot;) ;; false
+
foo kind?("foo") ;; false
foo kind?(&quot;Foo&quot;) ;; true
+
foo kind?("Foo") ;; true
foo kind?(&quot;Text&quot;) ;; false
+
foo kind?("Text") ;; false
foo kind?(&quot;Origin&quot;) ;; true
+
foo kind?("Origin") ;; true
foo kind?(&quot;Ground&quot;) ;; true
+
foo kind?("Ground") ;; true
foo kind?(&quot;DefaultBehavior&quot;) ;; true
+
foo kind?("DefaultBehavior") ;; true
foo kind?(&quot;Base&quot;) ;; true</pre>
+
foo kind?("Base") ;; true</source>
 
As you can see in this example, &quot;kind?&quot; can return true for several different texts.
 
As you can see in this example, &quot;kind?&quot; can return true for several different texts.
  
Line 32: Line 32:
 
: When looking at objects, there are two ways to get information about them, notice and inspect. If you want a brief description of an object where it's important that the description doesn't take up much space, notice should be used. If an exhaustive description is needed, inspect should be used instead. For some objects these both return the same thing, but for Origin mimics, the difference is large.
 
: When looking at objects, there are two ways to get information about them, notice and inspect. If you want a brief description of an object where it's important that the description doesn't take up much space, notice should be used. If an exhaustive description is needed, inspect should be used instead. For some objects these both return the same thing, but for Origin mimics, the difference is large.
  
<pre>Foo = Origin mimic
+
<source lang="ioke">Foo = Origin mimic
Foo x = &quot;blarg&quot;
+
Foo x = "blarg"
 
Foo y = 42
 
Foo y = 42
Foo notice ;; Foo_0x7CBDE6</pre>
+
Foo notice ;; Foo_0x7CBDE6</source>
 
The default notice for Origin mimics will combine the kind and the unique hex id for the object, and create a text of that. The &quot;notice&quot; method should be overridden to provide better information in most cases.
 
The default notice for Origin mimics will combine the kind and the unique hex id for the object, and create a text of that. The &quot;notice&quot; method should be overridden to provide better information in most cases.
  
Line 41: Line 41:
 
: In contrast to notice, inspect is used to get exhaustive information. If a composite object is asked for its inspect, a quite large dump of information will often be shown. For a new object the output will be smaller, but usually still larger than the notice for it.
 
: In contrast to notice, inspect is used to get exhaustive information. If a composite object is asked for its inspect, a quite large dump of information will often be shown. For a new object the output will be smaller, but usually still larger than the notice for it.
  
<pre>Foo = Origin mimic
+
<source lang="ioke">Foo = Origin mimic
Foo x = &quot;blarg&quot;
+
Foo x = "blarg"
 
Foo y = 42
 
Foo y = 42
Foo inspect println</pre>
+
Foo inspect println</source>
 
This will print:
 
This will print:
  
<pre> Foo_0x7CBDE6:
+
<source lang="ioke"> Foo_0x7CBDE6:
   kind                        = &quot;Foo&quot;
+
   kind                        = "Foo"
   x                            = &quot;blarg&quot;
+
   x                            = "blarg"
   y                            = 42</pre>
+
   y                            = 42</source>
 
If another representation makes more sense for inspection, &quot;inspect&quot; should definitely be overridden by custom objects.
 
If another representation makes more sense for inspection, &quot;inspect&quot; should definitely be overridden by custom objects.
  
Line 62: Line 62:
 
: The &quot;cell&quot; method can be used for two different things. The first one is to get access to a value without activating it, and the second is to get access to a cell based on a name that you don't know at the time you're writing the program. The &quot;cell&quot; method takes one argument that is the name of the cell to fetch. The fetching works the same as regular cell lookup, except that activation doesn't happen. This means that a condition will still be signalled if you try to get something that doesn't exist.
 
: The &quot;cell&quot; method can be used for two different things. The first one is to get access to a value without activating it, and the second is to get access to a cell based on a name that you don't know at the time you're writing the program. The &quot;cell&quot; method takes one argument that is the name of the cell to fetch. The fetching works the same as regular cell lookup, except that activation doesn't happen. This means that a condition will still be signalled if you try to get something that doesn't exist.
  
<pre>x = 42
+
<source lang="ioke">x = 42
 
cell(:x) ;; 42
 
cell(:x) ;; 42
  
Line 69: Line 69:
  
 
name = :foo
 
name = :foo
cell(name) ;; the value of foo</pre>
+
cell(name) ;; the value of foo</source>
  
 
; cell=
 
; cell=
Line 80: Line 80:
 
: If you want to get the names of all the cells an object contains, you can get that with cellNames. By default, cellNames will only return the names of cells that belong to the receiver, but if an argument of true is sent to the call, the resulting list will contain the names of all cells of all mimics too.
 
: If you want to get the names of all the cells an object contains, you can get that with cellNames. By default, cellNames will only return the names of cells that belong to the receiver, but if an argument of true is sent to the call, the resulting list will contain the names of all cells of all mimics too.
  
<pre>x = Origin mimic
+
<source lang="ioke">x = Origin mimic
 
x f = 42
 
x f = 42
 
x cellNames ;; return [:f]
 
x cellNames ;; return [:f]
  
x cellNames(true) ;; return a long list, including :f</pre>
+
x cellNames(true) ;; return a long list, including :f</source>
  
 
; cells
 
; cells
 
: Just like cellNames return the names of all the cells, the &quot;cells&quot; method will return a Dict of all the cells with their values. And just like cellNames, cells take an optional boolean argument on whether to include the cells of mimics too.
 
: Just like cellNames return the names of all the cells, the &quot;cells&quot; method will return a Dict of all the cells with their values. And just like cellNames, cells take an optional boolean argument on whether to include the cells of mimics too.
  
<pre>x = Origin mimic
+
<source lang="ioke">x = Origin mimic
 
x f = 42
 
x f = 42
 
x cells ;; return {f: 42}
 
x cells ;; return {f: 42}
  
x cells(true) ;; return a large dict, including f: 42</pre>
+
x cells(true) ;; return a large dict, including f: 42</source>
  
 
; mimics
 
; mimics
Line 134: Line 134:
 
: Update the message with a new name. From this point on the message will only have that name, so doing this on a message that is part of an existing message chain will change the behavior of that code:
 
: Update the message with a new name. From this point on the message will only have that name, so doing this on a message that is part of an existing message chain will change the behavior of that code:
  
<pre>msg = Message fromText(&quot;2 + 1&quot;)
+
<source lang="ioke">msg = Message fromText("2 + 1")
msg next name = &quot;-&quot;
+
msg next name = "-"
msg code ;; &quot;2 -(1)&quot;</pre>
+
msg code ;; "2 -(1)"</source>
  
 
; Message prev
 
; Message prev

Revision as of 09:19, 26 January 2009

Introspection and reflection

Ioke supports quite fancy introspection and reflection capabilities. In Ioke, reflection includes the ability to change data dynamically, as well as introspect on it. Since the message based structure of a program is available at runtime, most things can be changed dynamically. The internal structure of a program is also very easy to inspect.

All objects in Ioke have some core methods that are used to look at them. Some come from Base, and some come from DefaultBehavior. The rest of the reflection and metaprogramming capabilities belong to the Message kind.

kind
Should be a text that gives the full name of the kind this object is closest mimic to. Except for nil, true and false, this will return a text that starts with a capital letter.
Foo = Origin mimic
Foo mimic kind println

Foo Bar = Origin mimic
Foo Bar mimic kind println

This code will first print "Foo", and then print "Foo Bar", since an object assigned to a cell with a capital initial letter will get a new kind value.

kind?
Takes one text argument and returns true if the object has that kind anywhere in its mimic chain.
Foo = Origin mimic
foo = Foo mimic
foo kind?("foo") ;; false
foo kind?("Foo") ;; true
foo kind?("Text") ;; false
foo kind?("Origin") ;; true
foo kind?("Ground") ;; true
foo kind?("DefaultBehavior") ;; true
foo kind?("Base") ;; true

As you can see in this example, "kind?" can return true for several different texts.

notice
When looking at objects, there are two ways to get information about them, notice and inspect. If you want a brief description of an object where it's important that the description doesn't take up much space, notice should be used. If an exhaustive description is needed, inspect should be used instead. For some objects these both return the same thing, but for Origin mimics, the difference is large.
Foo = Origin mimic
Foo x = "blarg"
Foo y = 42
Foo notice ;; Foo_0x7CBDE6

The default notice for Origin mimics will combine the kind and the unique hex id for the object, and create a text of that. The "notice" method should be overridden to provide better information in most cases.

inspect
In contrast to notice, inspect is used to get exhaustive information. If a composite object is asked for its inspect, a quite large dump of information will often be shown. For a new object the output will be smaller, but usually still larger than the notice for it.
Foo = Origin mimic
Foo x = "blarg"
Foo y = 42
Foo inspect println

This will print:

 Foo_0x7CBDE6:
  kind                         = "Foo"
  x                            = "blarg"
  y                            = 42

If another representation makes more sense for inspection, "inspect" should definitely be overridden by custom objects.

uniqueHexId
This method is used to return a text that contains a unique hex identity for an object. This text is guaranteed to be unique within a virtual machine for any object, and is the mechanism that "inspect" and "notice" uses.
cellSummary
Calling "inspect" on any Origin mimic will dispatch to "cellSummary", which displays all the cell information about a specific object.
cell
The "cell" method can be used for two different things. The first one is to get access to a value without activating it, and the second is to get access to a cell based on a name that you don't know at the time you're writing the program. The "cell" method takes one argument that is the name of the cell to fetch. The fetching works the same as regular cell lookup, except that activation doesn't happen. This means that a condition will still be signalled if you try to get something that doesn't exist.
x = 42
cell(:x) ;; 42

x = method()
cell(:x) ;; the method object

name = :foo
cell(name) ;; the value of foo
cell=
Just as with "cell", "cell=" can be used to set cells that you don't know the name of at the time of writing the program. As discussed in the chapter on assignment, cell= can also be used to set cells that can't be set in the regular way due to naming strangeness.
cell?
If you're not sure if a cell exists, using "cell?" is the way to find out. Give it a name and it returns true or false depending on if that cell exists.
cellNames
If you want to get the names of all the cells an object contains, you can get that with cellNames. By default, cellNames will only return the names of cells that belong to the receiver, but if an argument of true is sent to the call, the resulting list will contain the names of all cells of all mimics too.
x = Origin mimic
x f = 42
x cellNames ;; return [:f]

x cellNames(true) ;; return a long list, including :f
cells
Just like cellNames return the names of all the cells, the "cells" method will return a Dict of all the cells with their values. And just like cellNames, cells take an optional boolean argument on whether to include the cells of mimics too.
x = Origin mimic
x f = 42
x cells ;; return {f: 42}

x cells(true) ;; return a large dict, including f: 42
mimics
Returns a list of all direct mimics of the receiver.
mimics?
Takes one object as argument and returns true or false depending on if the argument is anywhere in the receiving objects mimic chain.
message
Takes one symbol argument and creates a new Message mimic with that argument as its name.
Message code
Returns a text that describes the code this message chain represents. It will hide some of the internal shuffling, but operators will be displayed using canonical form.
Message formattedCode
Returns a text that is formatted and indented in a canonical way. This method is used to generate the documentation code for DokGen, among other things.
Message evalArgAt
Takes the index of the argument to evaluate, and the ground to evaluate it on - returns the result of evaluating the argument.
Message fromText
Takes one text argument that should contain Ioke code, and returns the parsed message chain from that code, without evaluating it.
Message doText
Takes one text argument that should contain Ioke code, and returns the result of evaluating that code in the current context.
Message filename
Returns the filename where the receiving message was defined.
Message line
Returns the line number where the receiving message was defined.
Message position
Returns the position in the line where the receiving message was defined.
Message name
Returns the name of the message. The name of the message is what you generally talk about when saying you send a message. It can also be called the selector in other languages.
Message name=
Update the message with a new name. From this point on the message will only have that name, so doing this on a message that is part of an existing message chain will change the behavior of that code:
msg = Message fromText("2 + 1")
msg next name = "-"
msg code ;; "2 -(1)"
Message prev
Returns the prev pointer of this message, or nil if no prev pointer exists.
Message prev=
Sets the prev pointer of a message. The new value should be either nil or another message.
Message next
Returns the next pointer of this message, or nil if no next pointer exists.
Message next=
Sets the next pointer of a message. The new value should be either nil or another message.
Message sendTo
Sends a message to an object. It's important to realize that sendTo will not evaluate the whole message chain -- it will only send one message with arguments to an object.
Message keyword?
Returns true if this message is a keyword message, and false otherwise.

There are many more methods that can be used to do interesting introspection and reflection in Ioke. The reference documentation includes them all. Most of the interesting stuff can be found on the Message kind.

send
In many cases you want to activate something activatable in a cell, with a specific receiver. You can do this using send. You can send messages to most objects. Send takes one argument that should evaluate to the name of the message to send, and then sends along all other arguments given to send to the new message. These arguments will remain unevaluated, and will be evaluated at the leisure of the final method activated.