Importing from a library

You can import a module into the current namespace with import or require. This adds the exported bindings (or a subset of them) to the current lexical scope. It follows that these bindings (which are said to be imported) are determined at compile-time.

Syntax: import import-set*

An import declaration provides a way to import identifiers exported by a library (module). Each import-set names a set of bindings from a library and possibly specifies local names for the imported bindings.

import-set ::=
  | library-reference
  | (library library-reference )
  | (class class-prefix import-only-name*)
  | (only import-set import-only-name*)
  | (except import-set identifier*)
  | (prefix import-set identifier )
  | (rename import-set rename-pair*)
library-reference ::= ( library-name-parts [explicit-source-name])
import-only-name ::= identifier|rename-pair
explicit-source-name ::= string
rename-pair ::= ( identifier1 identifier2)

A library-reference is mapped to a class name by concatenating all the identifiers, separated by dots. For example:

(import (gnu kawa slib srfi37))

is equivalent to:

(import gnu.kawa.slib.srfi37)

as well as to:

(require gnu.kawa.slib.srfi37)

By default, all of an imported library’s exported bindings are made visible within an importing library using the names given to the bindings by the imported library. The precise set of bindings to be imported and the names of those bindings can be adjusted with the only, except, prefix, and rename forms as described below.

  • An only form produces a subset of the bindings from another import-set, including only the listed identifiers. The included identifiers must be in the original import-set. If a rename-pair is used, then the identifier1 must be in the original import-set, and is renamed to identifier2. For example:

    (import (only (kawa example) A (B1 B2) C (D1 D2)))

    is equivalent to:

    (import (rename (only (kawa example) A B1 C D1)
                    (B1 B2) (D1 D2)))

    The names A, B1, C, and D1 must exist in the library (kawa example). The bindings are accessible using the names A, B2, C, and D2.

  • An except form produces a subset of the bindings from another import-set, including all but the listed identifiers. All of the excluded identifiers must be in the original import-set.

  • A prefix form adds the identifier prefix to each name from another import-set.

  • A rename form:

    (rename (identifier1 identifier2) …)

    removes the bindings for identifier1 to form an intermediate import-set, then adds the bindings back for the corresponding identifier2 to form the final import-set. Each identifier1 must be in the original import-set, each identifier2 must not be in the intermediate import-set, and the identifier2s must be distinct.

A class form is a convenient way to define abbreviations for class names; it may be more convenient than define-alias. The class-prefix is concatenated with each identifier (with a period in between) to produce a classname. Each identifier becomes an alias for the class. For example:

(import (class java.util Map (HashMap HMap)))

This defines Map as an alias for java.util.Map, and HMap as an alias for java.util.HashMap. (You can think of the class form as similar to a only form, where the class-prefix names a special kind of library represented of a Java package, and whose exported bindings are the classes in the package.)

You can combine the class form with only, except, rename, and prefix, though only prefix is likely to be useful. For example:

(import (prefix (class java.lang Long Short) jl-))

is equivalent to

(import (class java.lang (Long jl-Long) (Short jl-Short)))

which is equivalent to:

(define-private-alias jl-Short java.lang.Short)
(define-private-alias jl-Long java.lang.Long)

Syntax: require featureName

Syntax: require classname [explicit-source-name]

Syntax: require explicit-source-name]

Search for a matching module (class), and add the names exported by that module to the current set of visible names. Normally, the module is specified using classname.

The form require has similar functionality as import, but with a different syntax, and without options like rename.

If a "sourcepath" is specified then that is used to locate the source file for the module, and if necessary, compile it.

If a 'featurename is specified then the featurename is looked up (at compile time) in the "feature table" which yields the implementing classname.

Syntax: provide featurename

Declare that 'featurename is available. A following cond-expand in this scope will match featurename.

Using require and provide with featurenames is similar to the same-named macros in SLib, Emacs, and Common Lisp. However, in Kawa these are not functions, but instead they are syntax forms that are processed at compile time. That is why only quoted featurenames are supported. This is consistent with Kawa emphasis on compilation and static binding.

For some examples, you may want to look in the gnu/kawa/slib directory.

Searching for modules

When Kawa sees a import or require it searches for either a matching source file or a previously-compiled class with a matching name.

For import we generate a classname by converting it in the same way module-name does: taking each identifier in the library-name-parts, mangling if needed, and concatenating the parts separated by periods.

If there is a matching module in any program-unit that is in the process of being compiled, we use that. This may be a file requested to be compiled with the -C command-line switch, or an extra library-definition in a file already parsed. Kawa will attempt to finish compiling the module and load the class, but if there are circular dependencies it will use the uncompiled definitions.

Next Kawa looks for a matching class in the context classpath. (There is special handling if the library-name starts with srfi, and certain builtin classes will have kawa.lib. prepended.)

Kawa also searches for a matching source file, described below. It uses the implicit source name (formed by concatenating the library-name parts, separated by "/"), as well as any explicit-source-name. The source file is parsed as a program-unit. It is an error if the program-unit does not declare a library (explicit or implicit) with the matching name.

If Kawa finds both a matching source file and a class, it will pick one based on which is newer.

Searching for source files

The Java property kawa.import.path controls how import and require search for a suitable source file. Example usage:

$ kawa -Dkawa.import.path=".:<foo fo>/opt/fo-libs/*.scm:/usr/local/kawa"

The value of the kawa.import.path property is a list of path elements, separated by ":". Each path element is combined with either the explicit source name or the implicit source name to produce a filename. If a matching file exists, then we have found a source file.

If a path element contains a "*" then the "*" is replaced by the implicit source name (without an extension). (Any explicit source name is ignored in this case.) For example, for (import (foo bar)) or (require the implicit source name is "foo/bar". If the path element is "/opt/kawa/*.sc" then the resulting filename is "/opt/kawa/foo/".

If there is no "*" in the path element, and there is an explicit source, then it is appended to the path element (or replaces the path element if the explicit source is absolute). Otherwise we use the implicit source, followed by the default file extension. (The default file extension is that of the current source if that is a named file; otherwise the default for the current language, which is ".scm" for Scheme.)

A path element that starts with a selector of the form "<library-name-parts>" is only applicable if a prefix of the requested module name matches the library-name-parts. If there is "*" in the path element, that is replaced by the corresponding rest of the implicit source name. For example if importing (fee fo foo fum) and the path element is "<fee fo>/opt/fo-libs/*.scm" then the resulting filename is "/opt/fo-libs/foo/fum.scm". If there is a selector but no "*", then the rest of the path element following the selector is combined with the explicit or implicit source as if there were no selector (assuming of course that the selector matches).

If the resulting filename is relative, then it is resolved relative to the current root. For example the source to a library with the name (x y) that compiles to a class x.y might be a file named /a/b/x/y.scm. Then the current root would be /a/b/ - that is the directory that results from removing the library name suffix from the file name.

More generally: assume the current module has N name components. For example the name (x y) (with the class name x.y) has 2 components. The current root is what you get when you take the current file name (say "/a/b/c/d.scm"), and remove everything after the N’th slash ("/") from the end (say "c/d.scm"; what remains (e.g. "/a/b/" is the current root. (If the current input source is not a named file, use the value of (current-path) with a "/" appended.)

The default search path is "." - i.e. just search relative to the current root.

Builtin libraries

The following libraries are bundled with Kawa:

(scheme base)
(scheme case-lambda)
(scheme char)
(scheme complex)
(scheme cxr)
(scheme cxr)
(scheme eval)
(scheme inexact)
(scheme lazy)
(scheme load)
(scheme process-context)
(scheme read)
(scheme repl)
(scheme time)
(scheme write)
(scheme r5rs)

The above are standard libraries as defined by R7RS.

(rnrs arithmetic bitwise)
(rnrs hashtables)
(rnrs lists)
(rnrs programs)
(rnrs sorting)
(rnrs unicode)

The above are standard libraries as defined by R6RS.

(kawa reflect)

Defines procedures and syntax for acessing Java objects and members: as field instance? invoke invoke-static invoke-special make primitive-throw set-field! set-static-field! static-field

(kawa expressions)
(kawa hashtable)
(kawa quaternions)
(kawa rotations)
(kawa regex)
(kawa string-cursors)

Various Kawa libraries add details.

(kawa base)

All the bindings by default available to the kawa top-level.

Importing a SRFI library

Importing a supported SRFI numbered N is conventionally doing using a (import (srfi N)) or the older R6RS syntax (import (srfi :N)) (with a colon, for historical reasons). You can also give it a name, as specified by SRFI 95. For example, any of these work:

(import (srfi 95))
(import (srfi 95 sorting-and-merging))
(import (srfi :95))
(import (srfi :95 sorting-and-merging))

You can also use (require 'srfi-N):

(require 'srfi-95)

Importing from a plain class

Note you can import from many classes, even if they weren’t compiled from a library-definition. The set of public fields in a class are considered as the set of exported definitions, with the names demangled as needed.

The module can be static module (all public fields must be static), or an instance module (it has a public default constructor).

If an imported definition is a non-static field and if no module instance for that class has been registered in the current environment, then a new instance is created and registered (using a "magic" identifier). If the module class either inherits from gnu.expr.ModuleBody or implements java.lang.Runnable then the corresponding run method is executed. (This is done after the instance is registered so that cycles can be handled.) These actions (creating, registering, and running the module instance) are done both at compile time and at run time, if necessary.

All the imported fields of the module class are then incorporated in the current set of local visible names in the current module. (This is for both instance and static modules.) This is done at compile time - no new bindings are created at run-time (except for the magic binding used to register the module instance), and the imported bindings are private to the current module. References to the imported bindings will be compiled as field references, using the module instance (except for static fields).