Function "annotations" are a feature that many languages support. They may take various forms such as decorators in Python or class and method annotations in Java -- having direct (like Python) or no direct (like Java) effect on the code it annotates. Factor has some similar features that I'll demonstrate below.
We can define a simple word to use in this example (that adds 2
to its input):
: foo ( x -- n ) 2 + ;
Watch
Using the tools.annotations vocabulary, we can attach a "watch" annotation that prints the inputs and outputs of a word when it is called:
IN: scratchpad \ foo watch
If you print the word definition, you can see how it was modified:
IN: scratchpad \ foo see
USING: math tools.annotations.private ;
IN: scratchpad
: foo ( x -- n ) \ foo entering 2 + \ foo leaving ;
You can call this word (either directly, or indirectly by calling another word which calls it) and see its inputs and outputs. A nice feature of this is that the UI lets you click on these values and see more detail (particularly useful if they are tuples or more complex objects):
IN: scratchpad 3 foo
--- Entering foo
x 3
--- Leaving foo
n 5
Reset
You can stop watching a word by calling "reset" on it (or right-clicking on its definition in the UI and choosing "reset") to remove all of its annotations. Currently, a word can only be annotated once.
IN: scratchpad \ foo reset
Timing
In addition to "watching", you can also use annotations to track the total running time of a word:
IN: scratchpad \ foo add-timing
IN: scratchpad 0 10,000 [ foo ] times .
20000
IN: scratchpad word-timing.
foo 0.000594456
Other
It also supports arbitrary annotations, such as adding "before" and "after" logic:
IN: scratchpad \ foo [ "hi" print ] [ "bye" print ]
[ surround ] 2curry annotate
IN: scratchpad 3 foo .
hi
bye
5
These annotations can be pretty powerful and were even used to build our code coverage tool.