Wednesday, December 19, 2012

Kawa - oldest functional language on JVM still going strong

by Per Bothner

So-called scripting languages are now very visible, but they have a long history, even on the Java platform. Of languages still in use and active development today, Kawa and Netrexx are (to my knowledge) the oldest, both created in 1996. (Java was publicly launched in 1995.) Kawa appears to have been the first scripting language to be compiled directly to Java bytescodes, and is the oldest still-active functional language on the JVM. Kawa was based on a simple Scheme interpreter written by Alex Milowski, but I re-wrote it as a compiler while I worked for Cygnus Solutions, probably the first company to commercialize Free Software. Kawa is now GNU software, available under an MIT license.

Kawa is still used for a number of projects. As an example MIT App Inventor (previously Google App Inventor) for Android is built on top of Kawa.

Scripting vs programming languages

Kawa tries to combine the advantages of scripting languages with those of Java-like programming languages.

Like other scripting languages, Kawa avoids boilerplate such as having to define a class and main method. Since Kawa is an expression language, the minimal Hello, world program is just:

"Hello, world!"

Macros allow syntactic extension, and can be defined in libraries just like functions. It is trivial to implement a domain-specific language on top of Scheme, at least as long as you use the core S-expression datum syntax. Kawa has convenient syntactic short-hands like colon notation.

Kawa is quite dynamic: It has eval, and a read-eval-print-loop. If you type in an expression or load a file to be evaluated, it is automatically(and quickly) compiled down to bytecode.

You don't need to specify the types of variables - but you can: Doing so helps document your program, may allow the compiler to generate faster code, and may allow the compiler to catch errors and inconsistencies.

Kawa also has the advantages a more conventional programming language, like Java or Scala. You can compile to a class file, which can be an application (with an automatically-generated main), an applet, a servlet, or other specified class. It has an optimizing compiler which does decent data-flow analysis and type interface. This combined with optional type declarations make it straightforward to write code that is as efficient as Java or Scala - and many times faster than languages like JRuby or Clojure. The compiler is good at detecting and reporting errors, which avoids many painful debugging sessions. Kawa's primary visibility boundary is a sourcefile modules, which is natural and easy for both human readers and compilers.

In the rest of this article I will touch on some cool features of Kawa; maybe one of them will inspire you to try it out.

Object construction

Kawa has a convenient terse syntax for object construction. For example, this creates a Swing JButton that calls do-it when pressed:

(javax.swing.JButton
  text: "Do it!"
  action-listener:
   (lambda (e) (do-it)))

Groovy has a SwingBuilder that allows similar compact object construction. However, Kawa's is built in: It works for any bean-like class with standard set or add methods. Kawa is also more efficient, since it doesn't create a helper object. Instead the compiler translates the constructor call to code like what you'd write by hand in Java.

Android

Of course sometimes just using the beans naming convention isn't quite enough to yield a pleasant constructor API. For example, in the Android API you construct a tree of View objects. Each View constructor requires a parameter which is the current Activity, which looks like this:

(TextView (this) text: "Hello world!")

The reference (this) to the current Activity is tedious boiler-plate. That is why Kawa defines some special handling so you can leave out the (this):

(TextView text: "Hello world!")

This special handling for View classes is not hard-wired but is defined in an Android-specific library.

Read how to build and run Android applications and more about Android View expressions.

JavaFX

Kawa also has some special handling to ease JavaFX programming. This page has a simple example and up-to-date instructions. Also check out two slightly older blog articles: an introduction, and about animation.

Self-configuring web server

It is easy to write web services using Kawa. No setup or additional software is needed if using the server built in to JDK (version 6 or later). Just start Kawa like this:

kawa --http-auto-handler / appdir --http-start 8888

Here is a web page script that replies back with the name of the requesting (client) host:

;; Hello world page script written in -*- scheme -*-
#<p>Hello, <b>&(request-remote-host)</b>!</p>

The script uses an XML literal with an embedded expression. Put this file in appdir/path, and point your browser to http://localhost:8888/path. Kawa will find the file, recognize the string -*- scheme -*- in the first line and realize it is a Scheme script, then compile (if necessary) and evaluate it, and return the result to the browser.

You can use the same page scripts on a servet container such as Tomcat or Glassfish, instead of using JDK's builtin server.

Lazy evaluation

A pure functional language uses lazy evaluation - i.e. an expression is only evaluated when the value is needed. Impure functional languages like Scheme use strict evaluation, familiar from Java and most commonly-used languages. Kawa has a hybrid functionality: The expression (delay E) evaluates to a promise P that will evaluate the expression E when requested. You can call (force P) to explicitly force the resulting promise: It returns the result of evaluating E. The expression E is only evaluated once, and the result remembered in case P is forced later.

The forms delay and delay are standard. Kawa also supports implicit forcing, as you'd find in a pure functional language: If the promise is used in a context that requires a real non-promise value, such as (* P 2) the P then the result is as you wrote: (* (force P) 2). It makes it more convenient to use lazy values.

Kawa also has futures; these are also automatically forced when needed.

Meta: this post is part of the Java Advent Calendar and is licensed under the Creative Commons 3.0 Attribution license. If you like it, please spread the word by sharing, tweeting, FB, G+ and so on! Want to write for the blog? We are looking for contributors to fill all 24 slot and would love to have your contribution! Contact Attila Balazs to contribute!

No comments:

Post a Comment