Friday, August 20, 2010

Why I like Factor

Factor is a relatively new language and implementation in the tradition of Forth, Lisp, and Smalltalk. Like Forth, Factor is concatenative and uses a postfix syntax. Also like Forth, Factor emphasises small procedures and constant refactoring. Like many Lisp and Smalltalk implementations, Factor compiles code into a loadable image. Like Lisp, Factor can perform arbitrary computation at compile time using macros while parse time evaluation allows the creation of new syntax forms.

Unlike Forth, Lisp, and Smalltalk, Factor is modern and unencumbered. Lisp suffers from an ossified specification, Smalltalk has lived inside its own image for so long it's out of touch with the rest of the world, and Forth provides few of Factor's higher level features like garbage collection and dynamic code updating.

Factor’s focus on correctness and efficiency is not commonly found in other modern ‘dynamic’ languages. The results speak for themselves.

1. Factor vocabularies are compiled to machine code. When using the interactive listener the code is compiled before execution (like SBCL).

2. Factor is fast. Not C fast, but SBCL fast.

3. Almost all structures are modifiable at runtime. This includes classes at any position in the hierarchy as well as FFI bindings. When reloading a modified vocabulary, definitions no longer present will be deleted from the running image. These changes are propagated to all dependent code and the changes to the running image are kept consistent.

4. A simple foreign function interface. No quirky header files or IDL necessary; everything is done from within Factor. No reloading of Factor necessary either: create bindings incrementally and test them as you go.

5. Deployment images. Factor’s deployment tool only loads code the resultant binary will run. Minimal image size for a hello world program is a few hundred kilobytes.

6. Common Lisp style condition system. Don’t let stack unwinding lose an exception’s context. Recover anywhere between where the exception is caught and where it was thrown.

Why having a competent designer pays off

In contrast to other popular languages like Ruby and Python, Factor does not suffer from limiting creeds like, “There should be one way to do it,” or from BDFLs who don’t see the value in useful language constructs discovered as early as the 70s. Here's the payoff...

7. Correct lexical scoping. Usually in Factor one uses its postfix syntax and data flow combinators, however it also sports a locals vocabulary defined entirely in factor which implements lexical scoping and lambdas. Despite the fact that this is an addition in a language where lexical variables are not the default, Factor's lexical scoping is correct and its lambdas are uncrippled. Python 2.x is unable to rebind a variable in a parent scope (3.x overcomes this by introducing a new keyword, ugh!), and Ruby only recently (1.9) gave blocks their own scope.

8. Usable higher order functions. Combinators are used in Factor all the time. For some unfathomable reason Ruby allows only one block argument per function while in Python the use of such esoterica as map and reduce is discouraged.

9. Tail call optimization. Yep, that’s right, that helpful recursion thingy. Another thing Python doesn't have because, oh I don’t know, ask Guido. Come to Factor and free your mind from loopiness!

10. Low, hi, and FFI. Factor scales well from highly abstracted garbage collected code, to micro optimization using inline ASM. Along the way, the FFI allows Factor quotations to be used as C callbacks, and provides factor-side memory allocation should you need to store values on the stack or in a memory pool.

11. Methods are orthogonal to classes. Generic words and their methods are defined outside classes. Adding a generic word to a preexisting class is as simple as defining it. Extensibility without nasty monkey patching or name clashes, and a nice fit with a hierarchy that can contain anything from tuples, to predicate classes and C structs. No hideously bloated base-class needed (I'm looking at you Smalltalk). If Programmer Pooh adds a display-in-opengl method to object he need not modify core code, nor will his method clash with any present or future methods on object.

Why having a smart community pays off

Smart, or at least willing to learn new things.

12. No whiners! Try educating a bunch of Java programmers in the utility of higher order functions or tail-recursion...

13. Macros, syntax, and combinators, oh my! If you don’t whine, you get cool stuff. Macros akin to those in Common Lisp, but hygienic like Scheme, because if you don’t have variables, you can’t capture them. Syntax words like Lisp’s reader macros, but better because no dispatch character craziness is necessary. Observe the usefulness of regular expressions that are syntax checked at parse time, or the EBNF vocabulary which compiles an inline EBNF description into parsing code. For higher order goodness check out Factor’s unique dataflow combinators. This is not your ancestor’s stack shuffling!

More stuff I like

14. Live documentation. Factor has live documentation ala Emacs, but prettier and better linked. The documentation is contained in separate files to the code it describes. For those of us who hate hunting for scratchings of code amid screeds of API comments, this is a good thing.

An acceptable Lisp?

Someone once wrote about Ruby being an acceptable Lisp. They were wrong. Ruby doesn’t have macros, reader macros, native compilation, or a REPL from which everything can be modified. (Oh, but it does have three different kinds of lambda!)

Factor isn’t an acceptable Lisp either. Factor is a mighty fine Lisp. Factor is better than Lisp. It has all the things that make Lisp great and more. Factor will make your code beautiful. Factor will cook you breakfast. Factor reads like English, (lisp (like (not))). All hail Factor!

Summation

I like Factor because it hits the sweet spot of pandering to nothing but being a great language. It lifts much of the good stuff from great languages of yore and gives them an improved spin. It hasn’t yet succumbed to the whining hordes of mediocrity. It is written by a team that really know what they are doing. If that doesn’t describe your language, then give Factor a try.

11 comments:

  1. I tried really hard to like factor but whenever I had to write even the simplest conditional statement I'd be stuck with something or other "unbalanced" for like an hour.

    I was pretty impressed with the speed of things though.

    ReplyDelete
  2. I like your enthusiasm. I'm not sure how much Factor really has to do with Lisp, since it is a stack language, but it really fun and inspiring. I haven't programmed much in Factor other than learning the basics of the language, but I can tell you that on those first few days I started playing with it I told everyone I met about this awesome programming language I was using. No one had any idea what I was talking about, but at least my girlfriend put up with me.

    Keep up with Factor. I follow what's going on in the Factor world so I can jump in when I get the time for an appropriate project.

    ReplyDelete
  3. I love Factor. It's my favorite language, but I worry about what could be considered "fanboyism". For example, there's no need to bash Java developers.

    It's great to have passion but remember, Factor could teach other languages & developers. There's no need to be antagonistic.

    I would add to your list the UI, in specific the Walker. :)

    ReplyDelete
  4. I'm totally with you... Factor is awesome! Keep up with your posts - it seems you have a thing with writing. Nice storyline :-)

    ReplyDelete
  5. Hi Guillermo,

    Yes, the walker is great. You're right about fanboyism too. I shouldn't have made that dig at Java programmers. Bad jedahu! o_o

    ReplyDelete
  6. "Unlike Forth, Lisp, and Smalltalk, Factor is modern and unencumbered."

    There is a lot of material available to learn these languages (papers, textbooks, tutorials).
    Care to point me to some, to learn Factor ?

    ReplyDelete
  7. Hi therac25,

    I suggest working your way through the Factor Handbook at http://docs.factorcode.org

    ReplyDelete
  8. "(lisp (like (not)))"

    I don't know a lot about factor, so I could be off the mark, but I find it ironic that a stack-based language is making fun of lisp for being backwards (the paren joke is valid, albeit a bit cliched, though).

    ReplyDelete
  9. Loved your article! Factor is exciting and it brings back fond memories:

    I fell in love with Forth in the early 1980s when I wrote a auto parts store application on a Tandy Xenix using ACE Forth. I used the 1981 edition of "Starting Forth", by Lee Brodie, which is now online. It is one of the funniest yet most instructive language tutorials I have ever read.

    Later I used Forth, Inc's, and an application built using it called "Savvy". Forth seemed to fade away, but after I moved to Linux in 1998 I kept in contact with Forth via the several minor versions of it that were often made available in Linux distros. Versions like gForth, yForth and Others. Some introduced color and a "Windows" API, but none seemed to be as extensive as Forth, Inc's version.

    Even though I retired two years ago I am really enjoying working my way through Factor. It is an order or two of magnitude better than the Forth of 1980.

    ReplyDelete
  10. Hi j baker,
    In factor, the data flows in the same direction as the text. In most applicative languages it flows in the opposite direction.

    Apply g to x, then f to the result...
    factor: g f
    lisp: (f (g x))
    most C-like languages: f(g(x))
    haskell: f . g (or g >>> f)

    In factor (and haskell with >>>), the order of application matches the textual order. It's not an important difference, just an interesting one.

    ReplyDelete
  11. (lisp (like (not))) is wrong

    We want to have lisp, so we start with

    (lisp)

    But we don't want lisp, we want something like lisp, so

    (like (lisp))

    But now we want something not that, so

    (not (like (lisp)))

    So... yeah.

    Moreover, the whole "reads like English" is false. `if`? `while`?

    ReplyDelete