Spice (programming language)

From Bauman National Library
This page was last modified on 8 June 2016, at 10:09.
Paradigm functional, expression-oriented
Designed by Dave Regett, Chris Dollin, Steve Leach
Website Spice

Spice was created in 1998 by Dave Regett, Chris Dollin and Steve Leach with purpose to simplify text or metadata documents with complexive hierarchy (especially XML and HTML) processing for programmists of mediocre qualification and to improve the processing in the same time. Including syntax recognizing Algol and function-orientation recognizing Common Lisp, having therefore some of their features, Spice nevertheless is mostly expression-oriented language.


Automatical memory allocation control

Programmer doesn't have to make routine control after memory allocation: if the dynamic object isn't being linked, its memory is freed.

Data typification

Both static and dynamic typification are valid. By default, types are run-time entities, and the type of object is dynamically detected. Nevertheless, we can determine the concrete type on describing a variable, that is important for optimization. If binding variable to an expression, the type is detected in compile-time.

Language orientation

Spice is an expression-oriented language: every construction, including cycles, returns value. Multivaluing is supported. Number of values is not detected on compilation.

Level of language

Spice is high-level: functions as values are supported, so is the syntax of lambda expressions.


Function overload is supporited widely -- much wider than in SmallTalk, Java or C++.


Namespaces are not supported. New overload can be done in every package where the function can be seen. Special syntax for overloaded function difference is not needed though.

Function and variable definitions

Spice language supports several types of functions: procedures, methods, constructors, etc. Call expression looks like F(X), where F is a name of procedure, and X is an argument. Nevertheless this is not the only way to call function. Each variable must be defined before use. Strings are constant sequences of Unicode characters, which can be accessed via standard notation s[i].


The language has Algol-like syntax, for example:

  • Every word consists of letters, digits and underbars, always starting with letter. Words are case-sensitive, have unlimited length Typenames start with upper-case letter, other names -- from lower-case one.
  • Comments are of two types:
    # single-row comment
    /* multirow comment start
       multirow comment end */

The language has got symbols used for marking:

  • simple markers: []{},;
  • compound markers, looking like sequences from set !@%^&*-+=|:.?/<>. As XML- and HTML-expressions supported, compound markers "</>", "</", "><" are not allowed.


Numeric literals

Integer and floating point number are used in the same way and view as in another programming languages: for example, floating points can be presented in plain view (with separator ".", ex. 10.034) or in exponential view (ex. -1.45e-3). Some other views are also possible:

  • human-readable view, influencing and output (1_057_048);
  • radix format for bases from 2 till 36 (2x1001011, 12xA43, 30xIfThenElse), while 0x is equal to the prefix 16x. If latin letters are possible, they are allowed in both cases;
  • unit format (49cm, 143miles, 2x10000bits, 0.5cubemetre), available only for radix based from 2 to 10. Unit part must be defined earlier and consist only letters.

String and symbolic literals

String literals start and end with quotes. There are some special symbol combinations starting with \, which allow coding special symbols. This syntax reminds C-like languages. In addition, there are also following types of formats:

  • \&stuff;, where stuff is a valid HTML expression.
  • \(Expression) -- for regular expression format.
  • If after \ there is one of the following symbols: "[]{}|*%?" -- it is interpreted as a protected plain symbol both in strings and regular expressions.
  • Other symbols are not allowed to be used after \, if only future specifications of language don't allow them.

Symbolic literals start and end with single quotes. They are interpreted as a sequence of symbols.

Regular expression literals

Regular expression syntax has two forms: traditional and native -- which differ a little. Common constructions are:

  • symbol classes: [XYZ];
  • grouping: {S};
  • repetition: E*, is meant as Kleen iteration;
  • wildcard: ?;
  • alternation: X|Y.

Symbols from "[]{}|*%?" must be protected to be used as plain symbols.

Traditional model starts with // and ends with /. That's why symbol / also must be protected to be interpreted as a plain one. Native model starts with / and ends with a quote, that's why it must not have unprotected quotes.

Top-level syntax

Spice program consists of collection of packages that consist of header (identifier name and imports list) and body (definitions of variables, functions, class, enumerables, etc.)

Program syntax

    [(Spice)] (Package* | PackageBody)

Modifier syntax

Parameter MarkedModifier may be public, protected or private. The syntax of definition is like following:

    | '[' Name [(MarkedArgument)]** ',' ']'

Here MarkedArgument is a round-bracketed regular expression literal.


Are deifned in following template:

    MarkedModifier 'package' PackageName Facets PackageBody

The PackageName always ends by dot. The dot in the middle of the name means extension from another package.


We can declare imports from another packages into PackageBody:

    MarkedModifier 'import' OpenModifier PackageName [('from' Expr)]

Note that the last argument is not necessary.

Procedure definition

Full definition contents:

    'define' Modifier* [(':')] Header ProcedureBody 'enddefine'

Modifier is one of the literals: 'method', 'function', 'generic', 'init', 'specific'.

Header is a free-content combination of following blocks:
('returns' Type), ('extends' CommaExpr), ('super' Header)

Variable definition

    MarkedModifier NameDecl

MarkedModifier has values 'val' или 'var', NameDecl are the permitted names (one or more). If more than one, they're separated by commas.

Class definition

    'define' Modifier 'class' Name
    # Declare fields and methods here#

Small syntax


String, symbolic or numeric literals.


Names of prefix or infix operations start with symbol '@'. Postfix ones start with '@' or without it, and are called from argument afetr dot. Assigning operator is :=. Accessing to a class field is ->. Reversal operators for them are =: и <-.

Call expressions

Infix and prefix call expressions mean the same and can be used in all ways:


Lambda expressions

    '(' Args '=>' StatementSeq ')'

or, what's the same,

    'fun' Args '=>' StatementSeq 'endfun'

XML-like expressions

Are formed as valid XML notation.

branching and cycles

  • Binary branching: starts with if or unless (which means "if not");

If branch operator is unless, the end of block must be endunless. By the way, it is possible to use elseif Branch instead of else block. We can use also do instead of then with the same meaning.

  • Cycles:
    • repeat -- post-conditional;
    • for -- pre-conditional. Syntax using while is also possible.
  • Multiple branching operator switch.

Standard library

Data types

All data types start with upper-case letter. There is a special type Any, which is compatible to every other type. The special type Object is compatible to every example of any class.


General purpose type Number is compatible to every other numeric type:

  • integer: Small, BigInt.
  • floating point: Float.
  • ratios: Ratio.
  • complex numbers: Complex.

Another simple

  • logical: Bool.
  • symbolic: Char. Cannot be interpeted as small integer.
  • date and time types: Date, Time, DateTime.
  • function type Procedure.


  • general purpose string type: String.
  • unit identificator Unit.
  • file paths or URL: Pathname.


  • Tables: Table, FatTable.
  • Dictionaries: Lookup, Maplet.
  • Arrays: standard bracket notation a[i].

Standart functions and procedures

Both infix and prefix notation are supported in the same way. That's why infix notation must not be confused with only class method call. The most important functions are described below.

General data processing

  • Datatype return: x.typeOf.
  • Human-sensible output: x.printOn( s ), where s is an outputstream. Containers and structures are output in all members with standard separators.
    • If the outputstream is (StandardOutput), x.print may be used.
    • If the outputstream is (StandardReport), x.report may be used.
    • For output in the same way into string use x.toString.
    • Several values can be output into StandardOutput with following procedures:
      • print(x1, x2, ...) -- without new-line;
      • println(x1, x2, ...) -- with new-line.
  • Object copying: x.copy.
  • Equation check: equal( x, y ) or x == y.
  • Capacity of the object: x.length. The meaning is unique from such one in C++:
    • 0 for atomic objects;
    • number of objects in the container;
    • number of fields in the class example.

Math operations

  • Infix numeric operators:
    • +, -, *.
    • Division:
      • Floating point division: /. If result is guaranteed to be integer, it may be interpreted further as integer.
      • Ratio division: /:.
      • Integer division: ratio -- div (rounding the result to 0), remainder -- rem.
    • Comparison operators: <, >, <=, >=, == , / == . Their behaviour is standard. It is unwise to compare floating point numbers by == or / == .
  • Several functions:
    • Absolute value (and the same for complex): x.abs or x.magnitude.
    • min-max: x @min y, x @max y.
    • logarithm: x @logToBase y.
    • power: x @toPower y.
    • square root: x.sqrt. The exception is thrown if the result must be complex but complex number are not allowed in the code.
    • Rounding realnumber to integer ones: x.round, x.floor, x.ceiling.
    • Trigonometric and reverse trigonometric functions: x.sin, x.cos, x.tan, x.asin, x.acos, x.atan.

If these operations are done with numbers with units, be careful: the units must be compatitive and existing both for operands and results!

    # 1culon / 2second == 0.5umper. #
    # 1byte + 3byte == 4byte. #
    # 1byte + 5newton -> error. #


  • Strings:
    • String length s.length.
    • Copying with determining case: x.toLower, x.toUpper.
  • Arrays:
    • Array size: a.length.
    • Sorting-copying array with comparison function f: a @sortWith f. In-place sorting is made by a @sortInPlaceWith f.
    • Reverse-copying array: a.reverse. Analogically, a.reverseInPlace makes the same operation in place.
  • Tables and dictionaries:
    • Return keys from dictionary: l.explode.
    • Returning key-value pairs from dictionary: l.maplets.
    • Checking existance of key k: l @hasKey k.
    • Key-value pair: key == > value.

Input-Output Stream processing

I/O operations use tokens of types File, Pathname, Stream. They include such operations as:

  • s.streamFile -- returns what file is appropriate to s;
  • s.parsePath -- formates Pathname due to string parsePath;
  • f.openedOn -- tells what path has the opened file f got;
  • f.close -- closes the file if it hasn't closed yet;
  • f @readInto( b, w, l ) -- reading from opened file f into byte buffer b with offset w, but not more than l bytes;
  • f @writeFrom( b, w, l ) -- writing to opened file f from byte buffer b with offset w, but not more than l bytes.

Chances of improving development in Spice

Now most of popular programming languages have got native or binary libraries with functions for metadata documents processing, that's why Spice language is not significantly used in modern development. By the way, Chris Dollin (see [1], paragraph 23.1) considers exception mechanism implemented as in C++ and Java to be impropriate for Spice language style.


  1. Chris Dollin -- Technical Report for Spice, HP Laboratories Bristol, published on October 30, 2002.
  2. Статья о языке программирования Spice Russian, state from 17.01.2014.