Monday, September 24, 2012


As a diversion today, I added "color tab completion" to the Factor environment. I even made the color names render with their assigned color value:

For the curious, I extended the tools.completion vocabulary to implement a "colors-matching" word and then added a "colors-completion" type to the UI.

Tuesday, September 18, 2012

Faster Tables!

We've known for awhile that the Factor user interface is a little bit slow when displaying tables with many rows. I wasn't sure this was a big problem until a detailed bug report was filed (thanks @k7f!) that pointed out the vocabulary (with over 2,000 symbols in it) was "virtually unscrollable".

After poking around at the profiler output, I noticed that some UI gadgets had "baseline alignment" support which was used in the layout process. Some of these calculations were quite expensive and could easily be cached.

After a few changes, and introducing the concept of an "aligned gadget" which provides a mechanism to cache these alignment calculations, the original test case is almost 10 times as responsive as before!

This is available in the master branch on Github.

Monday, September 10, 2012

Watching Words

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 + ;


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


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


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 .

IN: scratchpad word-timing.
foo 0.000594456


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 .

These annotations can be pretty powerful and were even used to build our code coverage tool.