Guide:Introspection and Reflection

From IokeWiki
Revision as of 00:27, 26 January 2009 by Cv (talk | contribs) (Introspection and reflection)
Jump to: navigation, search

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.