Sunday, December 10, 2006

Making a Web Application in Factor, Part I: Introducing Factor

In a late night what-should-we-hack-next brainstorming session on #concatenative (irc.freenode.net), erg came up with the idea to make a "Recipes for Nerds" web application. Why? Because nerds need food, too. (Something low stress and fast so we can get back to the monitors! - erg)
Always one to complicate otherwise simple projects, I decided this is the perfect chance to bring you along for the joy ride that is my favorite programming language, Factor.

Intended Audience: Someone Like Me

When I first started learning Factor, I wasn't sure where to start. Factor is very well documented, but so is Linux! (dodges a tomato) Yes, I'll admit it. I'm not a glutton for punishment. Whatever hardships had to be endured for the sake of hackerdom, I'm not looking to endure them all over again.

Now, the Factor community is extremely helpful. It's just that I'm a little different from the rest. I'm a beginner that is drawn to Factor because I like good things. And so, this article is written for smart beginners.

Supplies

Before we start, grab a Factor binary from the Factor website. Everything that follows is written to the .86 release and may require tweaking to work with later releases.

Factor provides some integration with text editors that we won't use (optionally) until somewhat later in the article. I use TextMate for Mac OS X. Check out erg's Using .factor-boot-rc and .factor-rc for some clues on how to use vim, emacs, or jedit with Factor. For TextMate, drag Factor.tmbundle from contrib/textmate onto your TextMate icon. Then, create a file called .factor-rc in your home directory with the following lines:

USING: modules ;
"contrib/textmate" require


This will enable TextMate integration whenever you start Factor.

Three Reasons I Like Factor

Factor is Interactive

The Lispers out there are familiar with this idea, and it means that Factor is different from its popular, non-interactive brethren, such as Java and C, in some important ways.

Fire up Factor. What you see is the listener, an input loop that reads your commands and executes them. Type "hello" print to try it out. I think that's pretty cool! Try defining a word, which is a function in Factor: : hello "hello" print ;. Execute it: hello.

This means three interesting things with respect to your power as a Factor programmer. For one, say goodbye to the write-compile-run paradigm. Any change you make will be immediately effective, and any word you define is easily testable in the listener. I don't know about you, but I wrote an awful lot of System.out.println()'s in my day as a Java programmer.

Secondly, you can change, redefine, and wreak havoc on any part of the Factor language itself as you see fit. Only a small part of Factor is written in C and therefore non-negotiable; the rest is written in Factor itself!

Factor is Stack Based

In Factor, everything occurs with reference to the stack, which means there are no local variables or parameters. Oh, the sleepless nights spent agonizing over variable names!

For example, try:
"What is your name? " write readln "Hello, " write print

Where does the name go when it's read in? Onto the stack, where it remains until the last word, print, prints it to the screen. We can make things more clear by factoring our code, defining smaller, more easily understood words:
: ask-name "What is your name? " write readln ;
: greet-by-name "Hello, " write print ;
: make-conversation ask-name greet-by-name ;
make-conversation


And that's why it's called Factor! There is little programming and computational overhead to composing your program with many small words; executing a word is exactly the same as executing every word in its definition. Let's refine our definitions just a smidgen:

: ask-name ( -- name ) "What is your name? " write readln ;
: greet-by-name ( name -- ) "Hello, " write print ;
: make-conversation ( -- ) ask-name greet-by-name ;
make-conversation


The parenthesized part of these definitions is called a stack effect. ask-name is saying that it doesn't take anything from the stack (nothing to the left of the --) and it adds some object (name in particular, although this label doesn't matter to Factor) to the stack. The stack effect is an important part of keeping Factor programs readable.

Factor is Simple

All Factor ever does is execute sequences of words and literals. Factor has the simplest syntax of any language I've worked with. Here is a succinct, complete description of Factor's parser.

Until Next Time

In the next installment of this tutorial, we will learn about Factor's web framework, Furnace, and begin building our web app.

In the meantime, get to know factor! Your homework:
1) Translate (5 + 6) * (4 - 2 * 3) into Factor code.
2) Define a factorial word. You'll have to use a control structure such as if or cond.

4 comments:

PLTaddict said...

Hi, good work!

I've a question: is possible to use factor in NON interactive mode, without the "ui listener"?

Student said...

Thank you for reading!

Yes, it is possible to use Factor "non-interactively" by invoking the command line option -shell=none

So I can have a file, hello.factor, which contains:
USING: io ;
"Hello World!" print flush


And then run the file with: ./f factor.image hello.factor -shell=none

But, factor has much more to offer when used interactively!

I'm very interested in feedback from people new to Factor, so don't hesitate to comment again about your experiences!

Anonymous said...

Cmon. We are waiting for your follow-up. Can't wait to see it. Factor is the best thing I have seen for a long time.

Michael Judge said...

I'd be interested in a continuation of this series.