Posts Tagged “Lisp”

I’ve said It’s About the Libraries, and indeed, one of the major selling points of Clojure is that it can call Java libraries directly.

But there’s more to it than that.  Libraries are just one benefit to building Clojure on top of Java, or, more accurately, on top of Java the platform.

Look around you, and you’ll see that 99% of all the software in the world runs on just three platforms:

  1. Unix/C
  2. Java Virtual Machine
  3. .NET Common Language Runtime

Where did these platforms come from?  Let’s see:

  1. AT&T
  2. Sun
  3. Microsoft

Notice something?  All three were all developed by huge corporations.

Building a new platform isn’t just about writing the code.  In fact, very little of it is about code.  You need books, articles, conferences, workshops, and university courses.  You need multinational corporations to trust their entire business to your platform.  It takes millions of dollars and tens of thousands of hours of labor to create a new platform.  Think of the massive ad campaigns Sun ran for Java.  Can you do that?  Of course not.

So when you’re designing a new language, you have to build on an existing platform.  Most of the so-called “scripting” languages grew up on Unix, so they’re written in C.  Now, Unix/C is a great platform, still going strong after 40 years.  It provides powerful tools and standardized interfaces such as files, sockets, and pipes.

The problem is that each of the “scripting” languages has developed into its own mini-platform.  Perl, Python, and Ruby each define their own set of data structures for fundamental types like strings, lists, and maps.  The only “types” that Unix recognizes are text and binary.  You can’t exchange data between two languages without serializing everything to some agreed-upon format.  And you can’t do callbacks between languages below the level of a whole process.

The other problem with languages written in C is, well, C.  Pointers are hard.  Memory management is hard.  I know from bitter experience that Ruby libraries can have segfaults or memory leaks.  That just doesn’t happen in Java.

Clojure was created to leverage capabilities of Java-the-platform — garbage collection, dynamic code generation, JIT compilation, threads, locks — some of which are difficult to use effectively in Java-the-language.  To implement Clojure in C, for example, you would first have to build your own platform with these features.  That’s effectively what most Common Lisp implementations do, and they suffer because the Common Lisp world is too small to sustain its own platform.

The brilliant thing about Java-the-platform is that it allows many languages to coexist.  I can mix code written in Java, Clojure, JRuby, Jython, etc. and it’s pretty easy, because they all implement the same fundamental interfaces like java.util.List and  java.lang.Runnable.  For example, right now I have Hadoop (Java code) calling Clojure code calling JRuby code.  It all just works.

(The .NET CLR provides similar capabilities, and there is a Clojure CLR port.)

Comments 1 Comment »

I promised, in my previous post, that I would show you how to use the latest-and-greatest versions of Clojure and clojure-contrib in your Maven projects. Here’s that post.

Formos Software maintains a Maven server with nightly builds of Clojure and contrib at http://tapestry.formos.com/maven-snapshot-repository/

Here’s a complete pom.xml file with dependencies on both Clojure and clojure-contrib:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>YOUR.GROUP.ID</groupId>
  <artifactId>YOUR-PROJECT-NAME</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>YOUR-PROJECT-NAME</name>
  <dependencies>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure-lang</artifactId>
      <version>1.1.0-alpha-SNAPSHOT</version>
    </dependency>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure-contrib</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
  </dependencies>
  <repositories>
    <repository>
      <id>tapestry.formos.com</id>
      <name>Formos Software snapshot repository</name>
      <url>http://tapestry.formos.com/maven-snapshot-repository</url>
    </repository>
  </repositories>
</project>

Yes, that’s a pile of XML. But it’s not that complicated once you break it down.  Here’s what’s going on:

Dependencies

The <dependencies> section lists the libraries our project depends on.  We have one <dependency> for Clojure (called clojure-lang in the Formos repository) and one for clojure-contrib.  We’re depending on SNAPSHOT versions, which tells Maven to follow the most recent version on a particular branch.

The current development branch of clojure-lang is called 1.1.0-alpha-SNAPSHOT. The development branch of contrib, which has never had a formal release, is just 1.0-SNAPSHOT.

How did I find these version numbers?  I just looked at the repository in a web browser.  In the org/clojure/clojure-lang directory I found directories named for each development branch, 1.0-SNAPSHOT, 1.0.0-RC1-SNAPSHOT, and 1.1.0-alpha-SNAPSHOT.  I chose the latest one, 1.1.0-alpha-SNAPSHOT.  Then I did the same with clojure-contrib.

If you look inside a branch directory like 1.1.0-alpha-SNAPSHOT, you’ll find hundreds of files, one for each daily snapshot, named with timestamps.

Repositories

The <repositories> section tells Maven where to look for JAR files to download.  We added the Formos repository by specifying its URL.

The <id> and <name> tags inside <repository> are purely for our own reference.  Maven only cares about the URL. We could have used any id and name to describe the Formos repository; those names will be used in Maven’s console logging.

Managing Dependency Versions

The problem with tracking the latest snapshot is that sometimes there’s a release that breaks your code.  It might be a bug, or it might just be a change in behavior that makes the library incompatible with previous versions.

The Versions Maven Plugin can help to alleviate this problem by “locking” dependencies to specific releases and updating them in a controlled way.

First, we have to make the Versions plugin available to our project.  Do this by adding the following lines just before the final </project> in your pom.xml:

  <pluginRepositories>
    <pluginRepository>
      <id>Codehaus</id>
      <name>Codehaus Maven Plugin Repository</name>
      <url>http://repository.codehaus.org/org/codehaus/mojo</url>
    </pluginRepository>
  </pluginRepositories>

We’ve added a “plugin repository,” which is just a Maven repository that happens to contain Maven plugins.  (Technically, you don’t need to add this if your local Maven cache already has a copy of the Versions plugin, but putting it in pom.xml ensures that other developers coming to your project have access to all the same plugins.)

Now we can use the following mvn command:

mvn versions:lock-snapshots

This modifies your pom.xml file, setting the version string of every SNAPSHOT dependency to the current snapshot timestamp.  For example, when I run this command, I end up with the following:

  <dependencies>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure-lang</artifactId>
      <version>1.1.0-alpha-20090904.093041-38</version>
    </dependency>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure-contrib</artifactId>
      <version>1.0-20090904.093531-59</version>
    </dependency>
  </dependencies>

Now, whenever you build the project, you know exactly which Clojure release you’re getting.

So you work with a particular release for a while, then you want to upgrade to the latest one.  No problem!  Just run:

mvn versions:unlock-snapshots
mvn -U install

The first command modifies pom.xml, replacing all the timestamped version numbers with SNAPSHOT versions.

The -U option on the second command forces Maven to check for updated versions of all the snapshot dependencies.

Note: Both lock-snapshots and unlock-snapshots create a backup file called pom.xml.versionsBackup.  To remove this file (and accept the Version Plugin’s changes to your pom.xml) run:

mvn versions:commit

Likewise, to go back to the pom.xml file you had before the Versions Plugin messed with it, run:

mvn versions:revert

Explore

There’s a lot more to the Versions plugin, and to Maven dependency management in general.  Check the documentation for details.

Of course, the example here can be combined with the clojure-maven-plugin demonstrated in my previous post.  The syntax of the combined pom.xml file is left as an exercise for the reader.

One other thing: if you really want the absolute latest, up-to-the-second, still-hot-from-the-github version of something, there’s nothing for it but to use Git submodules.  I’ll demonstrate that in another post.

<dependencies>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure-lang</artifactId>
<version>1.1.0-alpha-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.clojure</groupId>
<artifactId>clojure-contrib</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<pluginRepositories>
<pluginRepository>
<id>Codehaus</id>
<name>Codehaus Maven Plugin Repository</name>
<url>http://repository.codehaus.org/org/codehaus/mojo/</url>
</pluginRepository>
</pluginRepositories>

Comments 3 Comments »

Update Sept. 4: How to get the latest builds of Clojure & Contrib

Maven is a touchy subject. People tend to have strong opinions about it. But like it or not, it’s the de-facto standard for dependency management in the Java world. Clojure lives in the Java world, so that means we have to live with Maven.

Here are some good things about Maven:

  • “Convention over configuration.”
  • Plugins are downloaded & installed automatically.
  • Handles dependencies of dependencies.
  • Declarative configuration, not imperative like Ant.
  • Only stores one copy of each JAR, shared by all projects.

Here are some bad things about Maven:

  • XML configuration file.
  • Verbose command line options.
  • Doesn’t track latest source code of projects. It does; see comments (Thanks, Tim!)
  • First run takes forever to download all the plugins.
  • Verbose console output.

In my estimation, the good outweigh the bad. And nothing outweighs the huge fact that Maven is already there.

So let’s develop a Clojure app using Maven.

Step 1: Install Maven.

If you don’t already have it, that is. This is pretty easy, just visit maven.apache.org and follow the instructions.

Step 2: Create a new project.

Type the following at the command line:

mvn archetype:generate

Maven will ask a series of questions:

  1. archetype: At the “Choose a number” prompt, press enter to accept the default project type, maven-archetype-quickstart.
  2. groupId: Enter a name to identify yourself in the global Maven namespace. All your Maven projects will use the same groupId. This is typically a reverse domain name in the style of Java package names. For example, I could use the groupId com.stuartsierra
  3. artifactId: Enter a name to identify this specific project in the Maven repository. For example, my-great-clojure-library
  4. version: Press enter to accept the default, 1.0-SNAPSHOT
  5. package: Press enter to accept the default, which is the same as your groupId.
  6. Confirmation: Press enter.

Now you have a directory named my-great-clojure-library containing the skeleton of a new Java project.

Step 3: Configure your pom.xml.

Go into your new project directory and edit the pom.xml file. The basic information will already be filled out.

We can remove the dependency on JUnit, so delete these lines:

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

Then we need to add the Clojure Maven plugin, which tells Maven how to compile Clojure source code. Before the final </project> tag, add these lines:

  <build>
    <plugins>
      <plugin>
        <groupId>com.theoryinpractise</groupId>
        <artifactId>clojure-maven-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <id>compile-clojure</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>

We also need to add Clojure itself as a dependency of our project (the Clojure Maven plugin does not do this automatically). Inside the <dependencies> tag, add the following lines:

    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure</artifactId>
      <version>1.0.0</version>
    </dependency>

That’s if you want the official Clojure 1.0.0 release. If you want a cutting-edge version, I’ll explain how in a later post.

Step 4: Delete Java sources.

Your project directory comes pre-equipped with two Java source directories at src/main/java and src/test/java. You can delete both of them, unless, of course, you’re developing a mixed Clojure-Java project.

Step 5: Add dependencies.

If your project does anything interesting, chances are it’s going to depend on some external Java libraries. You can find libraries in the public Maven repositories at mvnrepository.com. Search for a library name, and it will show you the code to put in your pom.xml file.

For example, say we want to use the Apache Commons IO library. At mvnrepository.com, we find the dependency code for this library:

  <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>1.4</version>
  </dependency>

And we can add that inside the <dependencies> section of pom.xml.

Step 6: Start coding!

Create the directory src/main/clojure. This is where all your .clj source files will go.

Follow the standard Clojure/Java convention for file names. That is, if you have a Clojure namespace called my.great.library, it should be in a file named src/main/clojure/my/great/library.clj

Step 7: Compile and install.

Run the following command:

mvn install

That will compile all your .clj source files into Java .class files, package them into a JAR, and install that JAR in your local Maven cache. On Unix-like systems, the cache should be at ~/.m2/repository/

Step 8: Live and learn.

There’s a whole lot more to learn about Maven. It’s a very flexible tool, and it can do almost anything. Yes, you will have to write some XML, but it’s really not that much.

Things I hope to cover in future posts:

  1. Using git submodules to track development versions of Clojure libraries.
  2. Running tests written in Clojure.
  3. Including .clj source files in your JAR.
  4. Creating a stand-alone JAR including all dependencies.
  5. Setting up a private Maven repository.

I hope this was a reasonable introduction to developing with Maven and Clojure, and that I have shown that Maven isn’t nearly as scary as people make it out to be. I think Maven suffered for a long time from poor documentation, but that’s changing rapidly. I found the (free) book Maven: The Definitive Guide extremely helpful.

Appendix: Complete pom.xml

Here’s the complete pom.xml file for the project I developed in this post:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.stuartsierra</groupId>
  <artifactId>my-great-clojure-library</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>my-great-clojure-library</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>org.clojure</groupId>
      <artifactId>clojure</artifactId>
      <version>1.0.0</version>
    </dependency>
    <dependency>
      <groupId>commons-io</groupId>
      <artifactId>commons-io</artifactId>
      <version>1.4</version>
    </dependency>
  </dependencies>
  <build>
    <plugins>
      <plugin>
        <groupId>com.theoryinpractise</groupId>
        <artifactId>clojure-maven-plugin</artifactId>
        <version>1.0</version>
        <executions>
          <execution>
            <id>compile-clojure</id>
            <phase>compile</phase>
            <goals>
              <goal>compile</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
</project>

Comments 11 Comments »

Update Sept. 3: Maven’s Not So Bad.

A lot of Ruby types come to Clojure and ask, “Where’s the package manager?” The answer is usually, “Maven or Ivy,” which isn’t really an answer.

I discussed this in the latter half of my Philly Lambda talk (PDF slides). The problem is that Clojure is built on Java, and any Clojure library that does something interesting is going to need some Java libraries beyond what the JDK provides.

Java has only one established dependency management system, Maven. (Ivy is an alternative, but it uses the Maven repositories.) Maven works, but it’s a big, complicated beast, built in the best giant-XML-configuration-file Java tradition. It’s also slow to accept new libraries into the public repositories. The central Maven 2 repository contains fewer than 700 libraries. Rubyforge, by contrast, lists over 8,000.

Maven seems to work well for large organizations that can benefit from setting up their own, private repositories, but it’s kind of a headache for the independent developer.

There’s a Clojure Maven plugin, some shell-based hacks like Corkscrew, and some Ivy-related code floating around, but none really provides what people want: one simple command to download and install all the dependencies for a project, without needing any XML.

What everyone wants, of course, is CPAN. Thousands of documented, tested modules for just about any task you could imagine, and quite a few you couldn’t (e.g., Acme::Buffy).

But CPAN was not created in a day. Most of its imitators (Rubygems, PEAR, Python Eggs) have failed to reach the same level of quality. Perl is also much older, and therefore more stable, than Python or Ruby. 10-year-old Perl code probably still works.

Part of this CPAN’s success, I think, has to do with the environment in it evolved. When Perl was the hot new language, running a web server was an expensive proposition. Even domain names weren’t cheap. If you were going to publish code on the web, there was a cost to doing so, either in time or money, so you wanted to make sure that it was worth publishing.

These days, when everyone has a blog and a Github account, sharing code is easy. Doing “git push” requires almost no thought, no investment of time. Why not release everything, even when it’s untested, undocumented, or unfinished?

So this weekend I started working on a package repository for Clojure. It was modeled it after CPAN, but designed to support anything that could be packaged in a JAR file, including compiled Java libraries and Clojure source code.

I got started. Then I thought, who would actually use this? Of the few dozen Clojure libraries that have been published on Github, only a handful are “production-ready.” Most aren’t even finished. Very few have been thoroughly tested. (I’m equally guilty in this regard.)

I concluded that it’s just too early. Clojure is a scarcely two years old. It just released “1.0″ this year, and is still developing rapidly. The libraries are evolving equally rapidly. If you want to build a project using, say, Compojure, the best way to do it is with Git submodules.

The one place a package manager would really be useful is in downloading and installing the standard Java packages that get used in almost every project, like the Apache Commons libraries. For this, Maven/Ivy works, if not brilliantly.

Update: another Maven helper: Clojure-POM

Comments 11 Comments »

The folks at Philly Lambda, a Philadelphia functional-programming group, were kind enough to invite me down to talk about Clojure last night. No video/audio recording, but here are my slides [PDF].

Comments No Comments »

My favorite programming language has made a 1.0 release!  [announcement]

Comments No Comments »

CANCELED: My presentation is canceled.  LispNYC will still meet at the Sunburnt Cow, 137 Avenue C, and I’ll be there to talk about Clojure.  But no slides, no video, etc.  My presentation is postponed to the June meeting.


I’ll be talking about my work with Clojure at LispNYC on the evening of Tuesday, May 12.   Time and location to be announced.   Slides and (hopefully) video available after the fact.

Possible topics:

  • Why Java + Lisp was such a great idea
  • Using Clojure with Java libraries like Hadoop & Solr
  • Deploying a web server with Clojure and Restlet
  • Clojure libraries I’ve written, such as test-is

Official announcement with time & location:
from LispNYC.org

Stuart Sierra presents: Implementing AltLaw.org in Clojure

This talk demonstrates the power of combining Clojure with large Java frameworks, such as:

  • Hadoop – distributed map/reduce processing
  • Solr – text indexing/searching
  • Restlet – REST-oriented web framework
  • Jets3t – Amazon S3

Join us from 7:00 – 9:00 at Trinity Church in the heart of the East Village. Afterward the discussion will continue at the Sunburnt Cow on 9th and C.

Directions to Trinity:

Trinity Lutheran
602 E. 9th St. & Ave B., on Tompkins Square Park
http://trinitylowereastside.org/

From N,R,Q,W (8th Street NYU Stop) and the 4,5 (Astor Street
Stop):
Walk East 4 blocks on St. Marks, cross Tompkins Square Park.

From F&V (2nd Ave Stop):
Walk E one or two blocks, turn north for 8 short blocks

From L (1st Ave Stop):
Walk E one block, turn sounth for 5 short blocks

The M9 bus line drops you off at the doorstep and the M15 is near get
off on St. Marks & 1st)

To get there by car, take the FDR (East River Drive) to Houston then go NW till you’re at 9th & B.  Week-night parking isn’t bad at all, but if you’re paranoid about your Caddy or in a hurry, there is a parking garage on 9th between 1st and 3rd Ave.

Comments No Comments »

There’s a big ‘ol thread going on down at comp.lang.lisp about Clojure vs. Common Lisp. I’m biased, of course, but I have to say that Clojure and Rich Hickey are holding their own against some of the top c.l.l. flamers.

But all the arguments about functional programming, software transactional memory, and reader macros miss what was, for me, the biggest reason to switch to Clojure. It’s about the libraries, stupid. Building on the JVM and providing direct access to Java classes/methods was the best decision in Clojure’s design. ‘Cause if it’s ever been done, anywhere, by anyone, someone’s done it in Java. Twice.

A few years ago, I tried to solve the Common Lisp library problem by writing a bridge from CL to Perl 5, and was laughed out of town. Rich Hickey, I’m told, spent years trying to bridge CL to Java, and never got very far. But Clojure works, and it works great. It’s a Lisp with a squintillion libraries. Who else can claim that?

So, if I wanted Lisp with Java libraries, why not use Kawa or ABCL … or heck, JRuby? Those are all fine projects, but they all suffer from mismatches between the “source” language (Scheme, CL, Ruby) and the “host” language (Java). There is never a one-to-one mapping between types in the source language and types in the host language. So you end up needing conversions like jclass/jmethod/jcall (ABCL) or primitive-static-method (Kawa). (JRuby is slightly better, but only because Ruby is closer to Java than CL/Scheme.)

Clojure doesn’t have this problem because it was designed from the ground up for the JVM. Clojure strings are java.lang.String, Clojure maps are java.util.Map, even Clojure functions are java.lang.Runnable (and java.lang.Callable). This makes it supremely easy to mix-n-match Clojure code with Java libraries and vice-versa. I know, because every day I use Clojure with complex Java libraries like Hadoop, Restlet, Lucene, and Solr. Everything just works. I don’t have to write any foreign-function interfaces or bridge code. In fact, using Java libraries in Clojure is often easier than using them in Java!

Clojure may not be a programming language for the next hundred years, as Arc aspires to be. But it’s a great language if you want to get stuff done right now.

Comments 11 Comments »

It’s interesting to see the first signs of rebellion against RSpec. I jumped on the RSpec bandwagon when it first appeared, mostly so I wouldn’t have to write “assert_equals” all the time. But while I liked and used RSpec, I don’t think it made my tests any better. If anything, they were a little bit worse. I found myself testing things that were not really relevant to the code I was writing, asserting obvious things like “a newly-created record should be empty.”

When I got interested in Clojure, one of the first things I wrote was a testing library called “test-is”. I borrowed from a lot of Common Lisp testing frameworks, especially the idea of a generic assertion macro called “is”. It looks like this:

(deftest test-my-function
  (is (= 7 (my-function 3 4)))
  (is (even? (my-function 10 2))))

This is pretty basic, but it’s sufficient for low-level unit testing. So far, I think that’s how the library has been typically used. There have been occasional requests, however, for RSpec-style syntax. I can see how this would be useful for testing at a level higher than individual functions, but I have come to believe that the added semantics of RSpec are not really necessary.

Right now, the test-is library is built on the same abstractions as Clojure itself. Tests are functions, so you can apply all the same tools that already exist for handling functions. Tests can be called by name, organized into namespaces, and composed. There is almost no extra bookkeeping code that I need to write to make all of this work.

In contrast, if I were to adopt the RSpec style, I would have to write code to call, store, and organize tests. That’s more work for me, and ultimately restricts the flexibility of the library for people who use it. Furthermore, RSpec has its own set of semantics, above and beyond the language itself, which must be learned.

This is my first experience supporting a library for anyone other than myself, and I don’t want to force anyone into a particular style. A library like RSpec is a complete environment that attempts to anticipate all possible usage scenarios, so it’s grown correspondingly complicated. I want to provide a set of small tools, that can be combined with other tools to do interesting things.

Of course, by making that decision I’m already dictating, to some extent, how the library can be used. But really, what I’m trying to do is set limits for myself. I will commit to providing a flexible, extensible set of functions and macros for writing tests. I am explicitly not trying to provide a complete testing framework. If someone wants to build an RSpec-style framework on top of test-is, more power to them. I will happily try to make test-is easier to integrate into that framework.

But there’s one other thing that struck me about that article that I linked to at the beginning — the idea of putting tests and code in the same file. I think that’s a great idea, and Clojure comes ready-made to implement it. Clojure supports the idea of “metadata” on definitions. You can attach a set of arbitrary properties to any object, without affecting the value of that object.

It’s easy to attach a test function as metadata on a definition in Clojure, but the syntax is a little ugly, and there is no easy way to remove the tests from production code. So I came up with in addition to my library, the “with-test” macro. It lets you wrap any definition in a set of tests. It looks like this:

(with-test
 (defn add-numbers [a b]
   (+ a b))
 (is (= 7 (add-numbers 3 4)))
 (is (= -4 (add-numbers -6 2))))

This is equivalent to adding metadata to the function, but the syntax is a little cleaner. I’ve also added a global variable, “*load-tests*”, which can be set to false to omit tests when loading production code.

I like having each function right next to its tests. It makes it easier to remember to write tests, and easier to see how the function is supposed to behave. So to the extent that test-is will promote a testing style, this is it. But it’s a pretty radical departure from the traditional style of testing, so I’m not sure how others will react to it.

Comments 5 Comments »

I dropped in to hear Rich Hickey talk about Clojure at the New York Semantic Web meetup group.  Some highlights:

• Some programs, like compilers or theorem provers, are themselves functions.  They take input and produce output.  Purely functional languages like Haskell are good for these kinds of programs.  But other programs, like GUIs or automation systems, are not functions.  For example, a program that runs continously for months or years is not a function in the mathematical sense.  Clojure is mostly functional, but not purely functional.

• Most Clojure programmers go through an arc.  First they think “eww, Java” and try to hide all the Java.  Then they think “ooh, Java” and realize that Clojure is a powerful way to write Java code.  Rich frowns upon “wrapper” functions in Clojure that do nothing but wrap a Java method.  Calling the Java method directly is faster and easier to look up in JavaDoc.

• Rich recommended a paper, Out of the Tar Pit, for a discussion of functional and relational techniques to manage state.

• Clojure’s data structures are persistent.  This isn’t persistent in the stored-in-a-database sense.  It refers to immutability.  For example, adding an element to a vector creates a new vector that shares structure with the old one.  Because all data structures are immutable, this is both safe and efficient.  Clojure’s hash maps, for example, have time complexity of log-base-32, which is so small it’s practically constant.

• The first thing Rich did when experimenting with the semantic web was to pull data out of the Jena API and get it into Clojure data structures.  That allows him to leverage the full power of Clojure’s data manipulation functions.  This opens up a world of possibilities that he wouldn’t have if he stuck with Jena objects.  Basically, having your data trapped inside objects is bad, because you’re limited to whatever methods those objects provide.  With generic data structures, you can re-use and compose all the functions that Clojure already provides.

Screencasts and code from the talk should appear soon — watch clojure.org or the Clojure Google group for an announcement.

Comments No Comments »