Friday, March 28, 2008

Recent Changes in Factor

Here are some things I've been working collaboratively with some other Factor devs lately.

cwd, cd, and pathname changes

The old way to change the current working directory was to call the cd word. This is now obsolete, and code that does this won't get the expected behavior anymore. A new word, normalize-pathname, is called before every top level word using paths and adjusts the pathname based on a new dynamic variable called current-directory.

To get pathnames relative to the Factor directory you used to use the words ?resource-path and resource-path. The code "resource:foo.txt" file-contents now does what "foo.txt" resource-path file-contents used to do, so user code should avoid calling resource-path on path literals.

Also, there's a new word called with-directory ( path quot -- ) that calls your quotation with a new current working directory and restores the old one when done. All of words that deal with reading and writing files have been updated to respect this change.

Using the cd word is still useful sometimes, like when calling with-fork ( parent-quot child-quot -- ) when you want the child process to inherit the current-directory variable as its current directory.

Pathnames in Factor are still strings, but may be either strings or pathname objects in the future.

IO Launcher Priorities

Since some Factor developers still use Windows XP on single-core laptops from 2004, tools.deploy now sets the child process to have a lower priority so that the system is still usable when deploying images.

{ "cmd" "/c" "dir" "/S" "\\" } >>command
+low-priority+ >>priority

BSD Port

Factor now supports FreeBSD, NetBSD, and OpenBSD 32 and 64bit versions. Please inform us of any bugs you find. Binary releases should happen within a week.

Fixing the Solaris port is next up, followed by the ARM Linux and WinCE port.

Random number generator protocol

Because we want to generate secure random numbers for the new web framework, the Mersenne twister algorithm just won't do as Factor's sole pseudo random number generator. So until we implement a Yarrow prng, the default prng for cryptography is /dev/random on Unix systems and the CryptGenRandom call on Windows. Does anyone have a suggestion as to which provider to use? I'm using PROV_RSA_AES right now, but I just chose it randomly from the list.

The random protocol is really simple.
GENERIC: seed-random ( tuple seed -- )
GENERIC: random-32* ( tuple -- r )
GENERIC: random-bytes* ( tuple n -- bytes )

M: object random-bytes* ( tuple n -- byte-array )
[ drop random-32* ] with map >c-uint-array ;

M: object random-32* ( tuple -- n )
4 random-bytes* le> ;
There are two ways to get randomness -- either 32 bits at a time, or several bytes at a time. The cool thing is that you only have to put a method on one of these words, and the other one is taken care of by the default method! Of course, if you don't define either, the callstack will overflow. You can define methods on both for efficiency if it makes sense.

Wednesday, March 12, 2008

Singletons in Factor

A singleton is a design pattern that only allows for a unique class that is only instantiated once. In other languages, singletons can contain global data, but why not just use a global to store global state instead?

In Factor, a singleton is simply a predicate class whose predicate tests if the class is identical to itself. Singletons are defined like this:
That's it! No messy boilerplate to copy and paste, no subtle reasons why your singleton might be wrong in some corner case. Using the singleton, we can replace some of the less elegant parts of the Factor core code and implement things in a simpler way.

For instance, until now the core words os and cpu have returned strings based on how the Factor binary is compiled. Soon, these strings will be parsed into whichever singleton they represent, allowing for generic dispatch. I wanted to have a cross-platform library for finding out basic hardware information about your computer, like how many cpus/cores, what speed, and how much RAM is in a machine. To do this without singletons, I had to redefine information already available as strings (the cpu and os words) as symbols. With singletons, this duplication can be removed. The same applies to the compiler code and loading libraries.

Here is the way the core supported operating systems can be defined using singletons.
UNION: windows winnt wince ;
Now we can dispatch on these to find the number of cores:
HOOK: #cpus os ( -- n )
M: macosx #cpus { 6 3 } sysctl-query-uint ;
M: winnt #cpus system-info SYSTEM_INFO-dwNumberOfProcessors ;
For loading code, the current idiom is this:
<< "alut" {
{ [ win32? ] [ "alut.dll" ] }
{ [ macosx? ] [ "/System/Library/Frameworks/OpenAL.framework/OpenAL" ] }
{ [ unix? ] [ "" ] }
} cond "cdecl" add-library >>
Using singletons, we can shorten this to:
"alut" {
{ win32 "alut.dll" }
{ macosx "/System/Library/Frameworks/OpenAL.framework/OpenAL" }
{ unix "" }
} add-library
The library is assumed to be 'cdecl', but if it were 'stdcall' you could specify this by adding a "stdcall" string after the libary name, thus making a triple instead of a pair. The amount of boilerplate is reduced and the programmer can be more productive and write fewer bugs.

The implementation of singleton is:
: define-singleton-class ( class -- )
\ word swap
dup [ eq? ] curry define-predicate-class ;
This generates code that looks like:
PREDICATE: word winnt \ winnt eq? ;
It makes a predicate class with a superclass of 'word' that you can dispatch on and only a single instance exists. Why are singletons so hard to define in some other languages?

Thursday, March 06, 2008

Google Summer of Code 2008 Project Ideas

The Factor project is applying for Summer of Code. Here are our project ideas.


  • Write a structure editor
  • Write a text editor
  • Write an IRC client
  • Write a package manager for Factor
  • Write a file manager

Enterprise Factor

  • Update the bindings to MySQL, Oracle, ODBC for the latest DB framework in extra/db
  • Add bindings for DB2, Informix, SQL Server, Sybase, etc
  • Write a MySQL binding in Factor instead of calling the C library to permit nonblocking I/O operation and avoid GPL licensing issues
  • Write high-level wrapper for OpenSSL binding which implements encrypted Factor streams
  • Write a SOAP stack
  • Improve the continuation-based web framework with ideas from Seaside

Embedded Languages

  • Improve the Prolog implementation in extra/prolog
  • Revive extra/lisp
  • Write an assembler to a microcontroller and cross-compile applications from within Factor
  • Write an infix math DSL
  • Write a 'language X' to Factor compiler, where X is C, Ruby, Python, Javascript, Elisp, etc

Miscellaneous Libraries

  • Write a binding and high level interface to zlib or implement gzip compression in Factor
  • Finish the tar library
  • Finish the packet sniffer libraries
  • Implement the math algorithm of your choice for extra/math
  • Implement the data structures described in Purely Functional Data Structures
  • Write a COM interface
  • Improve the JNI library
  • Write a JNI-like bridge for Android
  • Write a wrapper for Windows Mobile libraries to make calls and send SMSs
  • Integrate the zoneinfo timezone database with Factor's calendar library
  • Add more calendars to the library, such as Persian, Hebrew, Islamic, Chinese, Hindu, Buddhist

Factor VM

  • Write a GC profiler
  • Make GC memory areas shrink after garbage collection
  • Implement dtrace probes
  • Make continuations serializable

User Interface

  • Write a binding to an image manipulation library
  • Finish bitmap library
  • Improve the look of Factor's UI gadgets
  • Add drag and drop support
  • Add any of the following gadgets: tabs, syntax highlighting text editor using the xmode library, combo boxes, tables, trees, spinners
  • Implement native font rendering on Windows