Difference between revisions of "Guide:Introspection and Reflection"
(2 intermediate revisions by the same user not shown) | |||
Line 160: | Line 160: | ||
; send | ; 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. | : 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. | ||
+ | |||
+ | == Reflector == | ||
+ | |||
+ | In some cases you might work with an object that doesn't support the usual introspective methods. For writing certain types of code it is just necessary to be able to break apart an object from the outside. To be able to achieve this, Ioke now has something called a Reflector, which give access to several reflective operations from the outside. The general pattern is that the name gets "other:" prepended to it, and takes the object to operate on as the first argument. | ||
+ | |||
+ | The available methods are: | ||
+ | ; Reflector other<nowiki>:</nowiki>become!(other, into) | ||
+ | : The equivalent of <code>other become!(into)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cell(other, name) | ||
+ | : The equivalent of <code>other cell(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cell(other, name) = value | ||
+ | : The equivalent of <code>other cell(name) = value</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cell?(other, name) | ||
+ | : The equivalent of <code>other cell?(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cellNames(other) | ||
+ | : The equivalent of <code>other cellNames</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cellOwner(other, name) | ||
+ | : The equivalent of <code>other cellOwner(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cellOwner?(other, name) | ||
+ | : The equivalent of <code>other cellOwner?(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>cells(other) | ||
+ | : The equivalent of <code>other cells</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>documentation(other) | ||
+ | : The equivalent of <code>other documentation</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>documentation(other) = value | ||
+ | : The equivalent of <code>other documentation = value</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>freeze!(other) | ||
+ | : The equivalent of <code>other freeze!</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>frozen?(other) | ||
+ | : The equivalent of <code>other frozen?</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>is?(other, obj) | ||
+ | : The equivalent of <code>other is?(obj)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>kind?(other, kindName) | ||
+ | : The equivalent of <code>other kind?(kindName)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>mimic(other) | ||
+ | : The equivalent of <code>other mimic</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>mimic!(other, newMimic) | ||
+ | : The equivalent of <code>other mimic!(newMimic)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>mimics(other) | ||
+ | : The equivalent of <code>other mimics</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>mimics?(other, potMimic) | ||
+ | : The equivalent of <code>other mimics?(potMimic)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>prependMimic!(other, newMimic) | ||
+ | : The equivalent of <code>other prependMimic!(newMimic)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>removeAllMimics!(other) | ||
+ | : The equivalent of <code>other removeAllMimics!</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>removeCell!(other, name) | ||
+ | : The equivalent of <code>other removeCell!(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>removeMimic!(other, mimic) | ||
+ | : The equivalent of <code>other removeMimic!(mimic)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>same?(other, obj) | ||
+ | : The equivalent of <code>other same?(obj)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>send(other, message) | ||
+ | : The equivalent of <code>other send(message)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>thaw!(other) | ||
+ | : The equivalent of <code>other thaw!</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>undefineCell!(other, name) | ||
+ | : The equivalent of <code>other undefineCell!(name)</code> | ||
+ | |||
+ | ; Reflector other<nowiki>:</nowiki>uniqueHexId(other) | ||
+ | : The equivalent of <code>other uniqueHexId</code> |
Latest revision as of 20:11, 22 December 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.
Reflector
In some cases you might work with an object that doesn't support the usual introspective methods. For writing certain types of code it is just necessary to be able to break apart an object from the outside. To be able to achieve this, Ioke now has something called a Reflector, which give access to several reflective operations from the outside. The general pattern is that the name gets "other:" prepended to it, and takes the object to operate on as the first argument.
The available methods are:
- Reflector other:become!(other, into)
- The equivalent of
other become!(into)
- Reflector other:cell(other, name)
- The equivalent of
other cell(name)
- Reflector other:cell(other, name) = value
- The equivalent of
other cell(name) = value
- Reflector other:cell?(other, name)
- The equivalent of
other cell?(name)
- Reflector other:cellNames(other)
- The equivalent of
other cellNames
- Reflector other:cellOwner(other, name)
- The equivalent of
other cellOwner(name)
- Reflector other:cellOwner?(other, name)
- The equivalent of
other cellOwner?(name)
- Reflector other:cells(other)
- The equivalent of
other cells
- Reflector other:documentation(other)
- The equivalent of
other documentation
- Reflector other:documentation(other) = value
- The equivalent of
other documentation = value
- Reflector other:freeze!(other)
- The equivalent of
other freeze!
- Reflector other:frozen?(other)
- The equivalent of
other frozen?
- Reflector other:is?(other, obj)
- The equivalent of
other is?(obj)
- Reflector other:kind?(other, kindName)
- The equivalent of
other kind?(kindName)
- Reflector other:mimic(other)
- The equivalent of
other mimic
- Reflector other:mimic!(other, newMimic)
- The equivalent of
other mimic!(newMimic)
- Reflector other:mimics(other)
- The equivalent of
other mimics
- Reflector other:mimics?(other, potMimic)
- The equivalent of
other mimics?(potMimic)
- Reflector other:prependMimic!(other, newMimic)
- The equivalent of
other prependMimic!(newMimic)
- Reflector other:removeAllMimics!(other)
- The equivalent of
other removeAllMimics!
- Reflector other:removeCell!(other, name)
- The equivalent of
other removeCell!(name)
- Reflector other:removeMimic!(other, mimic)
- The equivalent of
other removeMimic!(mimic)
- Reflector other:same?(other, obj)
- The equivalent of
other same?(obj)
- Reflector other:send(other, message)
- The equivalent of
other send(message)
- Reflector other:thaw!(other)
- The equivalent of
other thaw!
- Reflector other:undefineCell!(other, name)
- The equivalent of
other undefineCell!(name)
- Reflector other:uniqueHexId(other)
- The equivalent of
other uniqueHexId