Vocabularies
Factor handbook ยป Guided tour of Factor

Prev:Combinators
Next:Tests and Documentation


It is now time to start writing your functions in files and learn how to import them in the listener. Factor organizes words into nested namespaces called vocabularies. You can import all names from a vocabulary with the word USE:. In fact, you may have seen something like
USE: ranges

when you asked the listener to import the word [1..b] for you. You can also use more than one vocabulary at a time with the word USING:, which is followed by a list of vocabularies and terminated by ;, like
USING: ranges sequences ;

Finally, you define the vocabulary where your definitions are stored with the word IN:. If you search the online help for a word you have defined so far, like prime?, you will see that your definitions have been grouped under the default scratchpad vocabulary. By the way, this shows that the online help automatically collects information about your own words, which is a very useful feature.

There are a few more words, like QUALIFIED:, FROM:, EXCLUDE: and RENAME:, that allow more fine-grained control over the imports, but USING: is the most common.

On disk, vocabularies are stored under a few root directories, much like with the classpath in JVM languages. By default, the system starts looking up into the directories basis, core, extra, work under the Factor home. You can add more, both at runtime with the word add-vocab-root, and by creating a configuration file .factor-rc, but for now we will store our vocabularies under the work directory, which is reserved for the user.

Generate a template for a vocabulary writing
USE: tools.scaffold "github.tutorial" scaffold-work

You will find a file work/github/tutorial/tutorial.factor containing an empty vocabulary. Factor integrates with many editors, so you can try "github.tutorial" edit: this will prompt you to choose your favourite editor, and use that editor to open the newly created vocabulary.

You can add the definitions of the previous paragraph, so that it looks like
! Copyright (C) 2014 Andrea Ferretti. ! See https://factorcode.org/license.txt for BSD license. USING: ; IN: github.tutorial : [2..b] ( n -- {2,...,n} ) 2 swap [a..b] ; inline : multiple? ( a b -- ? ) swap divisor? ; inline : prime? ( n -- ? ) [ sqrt [2..b] ] [ [ multiple? ] curry ] bi any? not ;

Since the vocabulary was already loaded when you scaffolded it, we need a way to refresh it from disk. You can do this with "github.tutorial" refresh. There is also a refresh-all word, with a shortcut F2.

You will be prompted a few times to use vocabularies, since your USING: statement is empty. After having accepted all of them, Factor suggests you a new header with all the needed imports:
USING: kernel math.functions ranges sequences ; IN: github.tutorial

Now that you have some words in your vocabulary, you can edit, say, the multiple? word with \ multiple? edit. You will find your editor open on the relevant line of the right file. This also works for words in the Factor distribution, although it may be a bad idea to modify them.

This \ word requires a little explanation. It works like a sort of escape, allowing us to put a reference to the next word on the stack, without executing it. This is exactly what we need, because edit is a word that takes words themselves as arguments. This mechanism is similar to quotations, but while a quotation creates a new anonymous function, here we are directly referring to the word multiple?.

Back to our task, you may notice that the words [2..b] and multiple? are just helper functions that you may not want to expose directly. To hide them from view, you can wrap them in a private block like this
<PRIVATE : [2..b] ( n -- {2,...,n} ) 2 swap [a..b] ; inline : multiple? ( a b -- ? ) swap divisor? ; inline PRIVATE>

After making this change and refreshed the vocabulary, you will see that the listener is not able to refer to words like [2..b] anymore. The <PRIVATE word works by putting all definitions in the private block under a different vocabulary, in our case github.tutorial.private.

You can have more than one <PRIVATE block in a vocabulary, so feel free to organize them as you find necessary.

It is still possible to refer to words in private vocabularies, as you can confirm by searching for [2..b] in the browser, but of course this is discouraged, since people do not guarantee any API stability for private words. Words under github.tutorial can refer to words in github.tutorial.private directly, like prime? does.