Static reflection is used to ask questions about the tasks in the program.  The most useful static reflection predicates are:

  • [CompoundTask ?task]
    is true if ?task is defined in terms of other tasks through methods.  That is, if it isn't a primitive task.  For example, in our family example, [CompoundTask Parent] and [CompoundTask Siblings] are true because Parent is defined by methods, but [CompoundTask Different] is false because it's a built-in primitive.  For most purposes, compound task is a synonym for a user-defined task.
  • [TaskCalls ?caller ?callee]
    is true if the task ?caller contains a call to the task ?callee.  Again, in our family example, [TaskCalls Sibling Parent] and [TaskCalls Sibling Different] are both true because the method for Siblings calls both those tasks.  But [TaskCalls Parent Sibling] is false because Parent doesn't have a method that calls Sibling.
  • [TaskSubtask ?task ?call]
    is true if ?task has a method that matches the call ?call.  This sounds like TaskCalls, but it's different.  For example, in our Starflight example, the query [TaskCalls ? Hue] will tell you what tasks call Hue.  But [TaskCalls ? [Hue pure]] will tell you what tasks specifically call Hue with pure as its argument.
  • [Method ?call ?subgoals]
    is true if one of the methods that would be run in executing ?call would execute the sequence of calls in the list subgoals.

These predicates work in all modes, save for Method which requires its first argument to be an input.  So you can use CompoundTask both to check whether something is a compound task, and also to enumerate all the compound tasks in your program.

Static reflection is useful in many ways.  It's particularly useful for debugging and design-rule checking.  Let's look at some examples now.

Previous: Reflection
Next: Program visualization