Writing a 3-D Multiplayer Game with Kawa and JMonkeyEngine

Per Bothner (Kawa) <per@bothner.com>

mikel evins (the Fabric) <mevins@me.com>


JavaOne October 2015; San Francisco [CON2111]

Who are we?



Demo Fabric features

Factors in language choice and design

Interactive and incremental program development

The Lisp family of Languages

Expression languages

Lisp prefix notation

Benefits of Lisp syntax

Lisps for the JVM

What is ABCL?

What is Clojure?

What is Kawa?

Some Kawa language features

Java/JVM integration

Kawa class definition

Property and method references

object creation

arrays and objects with children

Kawa Modules

Module implementation

DEMO - update in place

Performance - execution speed

multiple threads and side effects

Performance - start-up speed

Startup issue - number of classes

Startup issue - loading each function at startup

Performance - memory use

Re-loading code in Kawa

Building and tooling

mikel on clojure and its ecosystem

Clojure is embedded in a large and complex ecosystem, and choosing to use Clojure essentially means committing to that entire ecosystem.
The majority of learning Clojure is not learning the language;
it’s learning clojars and leiningen and nrepl and boot and ring and om and maven and datomic and ...

The Fabric development environment

No main function


standards and specifications

mikel's summary of Scheme and Kawa

  • Kawa is a particularly convenient implementation of a particularly convenient standard.

  • Scheme is a convenient standard because it’s small and mature.

    Its standards are well understood, flexible, and adaptable.

    It’s community, though small, is evergreen. Its partisans continue to contribute to the advancement of language design.

  • Kawa is a convenient implementation because it makes the cost of using a non-Java language about as low as it possibly can be.

    A single jar on your classpath is all you need to incorporate Kawa into your project.

Bottom line - why mikel chose Kawa

  • Kawa's startup time was far better

  • Kawa’s performance was generally better

  • Kawa made it much easier to work with JMonkeyEngine than either Clojure or ABCL:

    • Inheriting from Java classes is much simpler

    • Working with a traditional imperative, object-oriented library is easy in Kawa or ABCL, but more awkward in Clojure

  • Kawa toolchain is much simpler than Clojure’s

Bottom line - other considerations

  • ABCL wins on interactivity, expressiveness, and a robust REPL

  • Cjojure wins on size of community

  • Cjojure wins on elegant side-effect-free programming

  • ABCL and Kawa win in being standards-based

  • Clojure wins in tool support

Questions and answers

(More slides about Kawa after, if there is time.)

Soon: patterns

  • Variable names generalized to patterns in parameter lists and definitions:

      (! [x y] (make-a-list))

    Succeeds if (make-a-list) returns a list of size 2.

  • Conditional patterns use '?':

    (if (? pattern value) action-if-match action-if-nonmatch)
  • Common use case:

    (if (? x::T val) (use-as-T x) (not-a-T))
    This simplifies instanceof tests.

process literals

  • Simple syntax for creating and running a process:

    (define p1 &`{date --utc})
  • When you convert a process to a string, you gets its standard output:

    (->string p1)  ⇒ "Mon Oct 26 18:54:55 UTC 2015"
  • Simple process substitution:

    &{echo The time is &`{date --utc}}
  • The in: specifies standard input as a string (here document):

    &`[in: "Foo\n"]{tr a-zA-Z A-Za-z}  ⇒ "fOO"
  • A pipe is just a combination of these ideas:

    &`[in: &`{date --utc}]{tr a-zA-Z A-Za-z}

xml literals

  • An XML literal is a '#' followed by an XML element:

    #<p>The result is <b>final</b>!<p>
  • This evaluates to a DOM Element value.

  • You can substitue the value of an expression (a string or a Node):

    #<em>The result is &{result}.</em>

APL-style arrays

(define v1 [2 3 5 7 11 13])
(v1 2)  ⇒ 5
(v1 [3 1])  ⇒ [7 3]
(v1 [4 >=: 2])  ⇒ [11 7 5]
  • Supports assign/replacment of slices.

    Can change the side (insert/delete)

    Working on generalizing this to APL-style multi-dimensional arrays.


  • The syntax @lst is used in a call.

    It evaluates lst to a sequence (list or array).

    Each element of lst becomes a separate argument

  • If lst is [3 4 5]:

    (+ @lst) ⇒ (+ 3 4 5) — i.e. reduction.

  • Works well with array/list constructor:

    (int[] @lst 9 @lst) ⇒ [3 4 5 9 3 4 5]