-
Notifications
You must be signed in to change notification settings - Fork 1
Home
version 0.3.0
mikel evins
Bard is a small, simple dialect of Lisp with a small but useful set of built-in datatypes, a novel object system that supports polymorphic generic functions, and a few simple amenities for concurrent and distributed programming.
Bard is strongly influenced by its ancestors, Common Lisp, Scheme, and Dylan. It also takes influence from several other programming languages, including Smalltalk, Haskell, Lua, Erlang, Clojure, and others.
The Bard 0.3.0 interpreter is a simple AST-walking interpreter that implements a growing subset of Bard features, but which is not particularly fast.
Bard is mainly designed to make me happy, so it has an idiosyncratic set of features. It is a lexically-scoped Lisp with a single namespace, like Scheme. It discards some of the more obscure legacy names of Lisp functions and special forms in favor of names that I judge to be more readable. It implements full continuations, but does not yet expose them in the surface language (that's likely to change in the near future). Its functions are polymorphic and support multiple dispatch in the style of CLOS.
Bard has a novel object system that separates representation, taxonomy, and protocol into orthogonal concerns. Another way of putting it is that, while conventional object-oriented languages usually combine data representation, subtype relations, and the operations defined on a type into a single construct (typically called a "class"), Bard separates them. In Bard you can define a class without specifying how it's represented; you can define a data representation without associating it with any particular class; and you can freely define operations over both classes and representations. That means that, for example, you can define a List class with different representations to take advantage of different performance characteristics. You can also use the same representation as two or more different classes at the same time--for example you can use four bytes simultaneously as a packed array of characters, a vector of booleans, and a 4-byte integer, without type coercion, and without loss of type information.
Version 0.3.0 of Bard doesn't support inheritance. I've gone back and forth on this point several times. I like CLOS-style multiple inheritance, especially when method dispatch is done using the C3 algorithm. I often have use for inheritance.
On the other hand, inheritance adds considerable complexity to a language, and it's not needed to support useful polymorphism. I've therefore often experimented with leaving it out, and version 0.3.0 of Bard finds the language at one of those points where I've left it out.
The main thing I miss when using Bard without inheritance is the ability to define a default method that covers all the types in the language except those that are specifically specialized upon. A few versions ago I hit upon a comfortable compromise: Bard supports special treatment of the class Anything. If method dispatch fails to find a method matching an argument type, it looks for one matching Anything--and only Anything; not any other types. This expedient has mostly erased my need for inheritance.
Bard is pretty easy to build for Mac OSX, and with some additional effort, it can be built for Linux and Windows. When I judge that the 0.3.0 feature set is complete enough, I'll declare this version released and add downloads of prebuilt binaries for those platforms. If you want to work with the interpreter before I have a release prepared, drop me a line and I'll help you get it working.
A compiler and virtual machine for Bard 0.3.x are under active development, and have been for some time. The compiler is written in Bard, and runs on the interpreter; the VM is currently written in Gambit Scheme (as is the interpreter). I don't expect the VM to be a speed demon, but it should be substantially faster than the current interpreter.
I used Bard 0.2.x for about a year on a game-development project under contract. Although the interpreter is pretty slow, it was more than fast enough for our uses on that project. It served as an engine for reading game data and configuration files, for evaluating game rules during play, and for executing event-handlers during gameplay. The games developed were delivered on iOS, and Bard 0.2.x was built into them, packaged as a static library compiled for the iOS platform. I'm not presently maintaining that version of the interpreter, but one reason that the VM implementation is in Gambit Scheme is so that it remains relatively easy to port to iOS and Android.
You can find example code in the examples directory, and a basic reference to the language in docs/bard.md.
I have some specific plans for Bard. I've chosen to write a VM-based compiler rather than a native-code compiler because I want it to be easy to port to many different platforms, and because I want to support image-based development, using platform-independent image files. I've experimented with facilities that make it easy for one Bard VM to communicate with another, either on the same host or on different ones, and I intend for Bard VMs to be able to safely send arbitrary data (including procedures) to one another as messages.
To make a long story short, I want to wind up with a compact and pleasant Lisp with acceptable performance that I can run on a wide variety of systems, and use to build distributed applications. I want to be able to write web services with it, and scripts for system programming, and graphical apps on the Mac, and Windows and Linux, and apps for mobile iOS and Android devices. Really, I want to make it convenient enough to do all these things that I'll be able to write apps that span all of these platforms without too much pain and suffering.
The Bard VM follows a design that makes it straightforward for it to support procedures implemented as bytecodes, or as native code, or as foreign functions written in another language. The version of Bard used in the game project mentioned above interacted freely with Objective-C code on iOS. It's my intention that the bytecode interpreter should be reasonably fast, but that Bard should also support compilation to native code, and the use of foreign functions written in C or other languages, so that performance need not be an obstacle to its use.
As I've said, the primary design criterion is that it should make me happy to use it, but I'm always interested in the views of other people interested in Bard. Feel free to drop me a line if you want to ask questions or make suggestions.