Packages
rontolisp has a small namespace (package) system with a set of built-in packages, plus user-defined packages via defpackage:
cl— the standard package. All built-in functions, macros, special forms and the*package*variable belong here.cl-user— the default working package. It usescl, so standard symbols are available unqualified. The current package when a program starts. User definitions go here.rontolisp— a package for implementation-specific symbols.rlis a built-in nickname. It does not usecl. It owns theversionfunction.linalg— numpy-style vector/matrix operations (linalg:zeros,linalg:matmul,linalg:solve, ...), implemented once in Lisp source and available in every backend.lais a built-in nickname. It does not usecl. See the Vectors & Matrices guide.torch— a PyTorch-style tensor with reverse-mode automatic differentiation and annn-style module layer, the optimizers and the training-loop plumbing (torch:tensor,torch:matmul,torch:backward,torch:linear,torch:cross-entropy-loss,torch:adam,torch:step, ...) over thelinalgkernels, implemented once in Lisp source and available in every backend. It does not usecl. See the Neural Networks guide.geom— solid modeling over thelinalgkernels: rigid transforms, a scene graph and boundary-represented solids with a cached triangle mesh (geom:box,geom:cylinder,geom:attach,geom:mesh,geom:volume, ...), implemented once in Lisp source and loaded on first use, likelinalg. It reaches for nothing outsidelinalg, so it is available in every backend. It does not usecl. See the Solid Modeling guide.java— Java interop by reflection, usable only under the JVM interpreter (java -jar rontolisp.jar), not the compilers or the native binary. It does not usecl. It ownsnew,call,static,fieldandproxy; see the Java interop guide.objc— the Objective-C runtime and AppKit through the foreign function API, macOS only: the interpreter (java -jar rontolisp.jarand therontolispnative binary), a compiled.class/.jarand a--nativeexecutable for Apple silicon, never a.wasm. It does not usecl. It owns the names of LispWorks 8.1's Objective-C interface (invoke,invoke-bool,invoke-into,retain,release,define-objc-class,define-objc-method, ...), blocks (make-objc-block,with-objc-block, ...), the conditionsobjc-exceptionandns-error, and its ownon-main,data,bytesandobjectp; beside it,cocoaholds the Foundation structures and the notification observers, andflithe part of LispWorks' foreign language interface the manual's examples use (define-foreign-function, foreign objects and pointers). See the macOS GUI guide.appkit— a Cocoa widget layer overobjc(appkit:window,appkit:label,appkit:button, ...), implemented once in Lisp source and loaded on first use, likelinalg. It does not usecl. Same guide.metal— a Metal drawing surface on anappkitwindow overobjc(metal:attach,metal:library,metal:pipeline,metal:buffer,metal:frame,metal:run, ...): the layer, the device, the command queue and the render pass every Metal program writes identically. Implemented once in Lisp source and loaded on first use; macOS only, likeobjc, and it stands on its own —geomandsceneare not needed to use it. It does not usecl. Same guide.scene— a 3-D viewer forgeomsolids overmetal(scene:viewer,scene:add,scene:fit,scene:camera,scene:animate, ...): an orbit/pan/dolly camera, a ground grid, axis triads and an animation hook, with no per-triangle work in a frame. Implemented once in Lisp source and loaded on first use; macOS only, likemetal. It does not usecl. See the Solid Modeling guide.asdf— a limited, API-compatible subset of ASDF (system definitions):defsystemandload-system. It does not usecl. See the Systems guide.ql— a limited, API-compatible subset of Quicklisp:quickloaddownloads a system from the real Quicklisp distribution and loads it through theasdfsubset, andupdate-distrefreshes a dist's index.quicklispis a built-in nickname. It does not usecl. See the Systems guide.ql-dist— Quicklisp's distribution machinery, of which the one member a program writes isinstall-dist: it adds another Quicklisp-format distribution (Ultralisp, or any distinfo URL) to the distsql:quickloadsearches. It does not usecl. See the Systems guide.uiop— ASDF's portability layer, registered as 15 sub-packages (uiop/os,uiop/pathname, ...) thatuiopre-exports, so both spellings of a member name the same symbol. It does not usecl. See The uiop Package.usocket— a usocket-compatible shim over therontolisp:tcp-*socket built-ins (usocket:socket-connect,usocket:socket-listen, ...), implemented once in Lisp source; also registered as the built-in ASDF system"usocket". It does not usecl. See the TCP Sockets guide.
A symbol can be referenced with a package qualifier: package:symbol (e.g. cl:car, rontolisp:version) reaches the package's external (exported) symbols, and package::symbol reaches any of its symbols, internal ones included — the same single/double colon distinction as Common Lisp (see External and internal symbols). *package* holds the current package — as the package keyword find-package answers, so (eq *package* (find-package ...)) holds — and (in-package name) switches it (the name is a keyword, a symbol, or a string: :rontolisp, rontolisp, "rontolisp"). Like Common Lisp's, *package* is a dynamic variable read when a form runs: a function reads the package current at call time, (let ((*package* ...)) ...) binds it for the extent, with-standard-io-syntax binds it to cl-user, and setq assigns it. The standard Common Lisp names common-lisp and common-lisp-user are built-in nicknames for cl and cl-user, so portable (:use #:common-lisp) clauses and common-lisp:car references resolve; the shorthands rl and la are built-in nicknames for rontolisp and linalg, and quicklisp for ql. User packages can register their own nicknames with the defpackage :nicknames clause.
rontolisp:version returns the same information as rontolisp --version, as a property list (:version "0.1.0-SNAPSHOT" :build-timestamp "..." :git-commit "..." :git-branch "..."). Its timestamp and revision are whatever the running build was made from, so no fixed result is shown for it here.
Because the rontolisp package does not use cl, standard symbols must be qualified with cl: inside it, while version (which it owns) is available unqualified:
(in-package rontolisp)
(cl:print (version)) ; the rontolisp package owns version
(cl:print (cl:car '(1 2))) ; standard symbols need the cl: prefix here
;; (car '(1 2)) would be an error: Undefined symbol: car (use cl:car)
The default package cl-user is empty and uses cl, so ordinary programs do not need any qualifiers.
External and internal symbols
As in Common Lisp, each package distinguishes its external (exported) symbols from its internal ones, and the two qualifier spellings differ in reach:
package:symbol(single colon) references an external symbol only.package::symbol(double colon) references any symbol of the package, internal ones included.
The built-in packages export their entire documented API: every standard cl
symbol is external, and so are all the rontolisp and java functions in this
manual (so the double colon is never required for them, though
rontolisp::version is also accepted and means the same as
rontolisp:version). Internal symbols follow the % prefix convention — for
example rontolisp::%json-parse, the fixed-arity helper behind
rontolisp:json-parse — and are
implementation details that may change without notice. cl-user exports
nothing, like the Common Lisp COMMON-LISP-USER package, so on the rare
occasion a cl-user symbol needs a qualifier it is written cl-user::name.
A single-colon reference to a non-external symbol is an error at read/compile time:
CL-USER> (rontolisp:%json-parse "1")
Error: The symbol %json-parse is not external in the rontolisp package (use rontolisp::%json-parse)
A package's export set comes from its definition — the built-in packages export
their documented API, a user-defined package its (:export ...) clause — and
export/unexport adjust it
afterwards. A symbol defined while (in-package rontolisp) is in effect is
interned into the rontolisp package as an internal symbol, so from other
packages it must be referenced with the double colon.
Exporting changes which qualifier reaches a symbol, never which symbol it is,
so an export may come before or after the definitions it publishes. One
deviation from Common Lisp: a symbol exported after it was first named keeps the
double colon when printed from a package where it is not accessible — the
qualifier is stored with the symbol here rather than recomputed at print time —
though both spellings name the same symbol.
Whether a qualifier is printed at all follows Common Lisp's accessibility rule:
prin1/print (and ~S) print no qualifier for a symbol accessible in the
current *package* — the package's own symbol, one inherited through :use as
an external, or an imported one — and pkg:name / pkg::name otherwise;
princ/~A never print one. So under (in-package :mypkg) the helper below
prints as HELPER, and from cl-user as MYPKG::HELPER. One gap: a cl-user
symbol or a standard symbol printed from a package where it is not accessible
prints bare rather than as COMMON-LISP-USER::name / COMMON-LISP:name.
User-defined packages (defpackage)
New packages are defined with defpackage:
Like in-package, defpackage is a literal, top-level directive consumed at
read/compile time, so packages are defined in source order, before any use.
The supported clauses are (:use package...), (:export symbol...),
(:nicknames name...), (:import-from package symbol...),
(:shadowing-import-from package symbol...), (:shadow symbol...) and
(:intern symbol...), plus (:documentation "...")/(:size n) which are
accepted and ignored; the name and the clause arguments are keywords, bare
symbols, strings, characters (#\H names "H"), or uninterned symbols
(#:name, the portable defpackage idiom). A :shadowed name always resolves to
the package's own symbol inside the package -- never to the cl (or any used
package's) symbol of the same name -- so a library can define its own
digit-char-p or defconstant; :intern adds a name the package owns without
exporting it -- unless a used package exports the name, in which case the
package inherits that symbol, as in Common Lisp. Any other clause is an error, and so is using a
package that does not exist yet. :size and :documentation may each appear
once; the names given to :shadow, :shadowing-import-from, :import-from
and :intern must be pairwise disjoint, as must those of :intern and
:export (a program-error). Importing a name the source package does not
have is a package-error whose continue restart interns the name there;
since rontolisp does not record the symbols a program merely reads, this is
checked only for a package made by defpackage/make-package that no source
has been read into yet. A defpackage that runs at run time (inside a function
body, or through eval) signals these as conditions a handler can catch; a
top-level one fails at read/compile time. A defpackage naming a package that already
exists MODIFIES it (Common Lisp's rule): the clauses merge into what is there,
which is what lets a library declare a package rontolisp has already seeded.
A name that is another package's nickname stays an error.
:usemakes the external symbols of the used packages visible unqualified, as in Common Lisp — internal symbols of a used package still need the double colon. Without a:useclause nothing is inherited (like SBCL), soclsymbols would need thecl:prefix; ordinary packages should say(:use :cl)(or, portably,(:use #:common-lisp)). When several used packages export the same name, the first package in:useorder wins (Common Lisp signals a conflict instead).:exportdeclares the package's external symbols. Symbols interned later (adefununder(in-package name)that is not in the:exportclause, a free variable) are internal, exactly like the built-in packages. A name the package inherits instead of defining -- a standard name throughcl((:use :cl) (:export #:car)) or a used package's export -- is re-exported:mypkg:cariscl'scar, and a package usingmypkginherits that symbol even withoutcl.:nicknamesregisters alternate names that resolve everywhere the canonical name does (in qualifiers,in-package,:use, ...). A nickname colliding with an existing package or nickname is an error — the built-in nicknames (common-lisp,common-lisp-user,rl,la,quicklisp) are reserved the same way as the built-in package names.:import-frommakes the named symbols of one package visible unqualified without using the whole package. Resolution is textual: an imported name resolves to the source package's canonical spelling, so importing and then re-exporting a symbol makesmypkg:namerefer to the original definition.
use-package is the runtime form of the :use
clause, and follows the same read/compile-time rule as in-package: a literal
top-level (use-package :mypkg) widens the current package's use list for the
forms that follow it, on every backend.
unuse-package is its inverse,
export, unexport and
import follow the same rule.
make-package is the runtime tier beside this
read/compile-time one: it creates an empty package (upcased name, :use
entries that must already exist), rename-package
renames one and delete-package drops one, with
failures signalling a catchable package-error. Read/compile-time packages are
immutable at run time -- renaming or deleting one signals. Which tier a
defpackage product lands in depends on who resolved it: a compiled program
bakes its spellings, so its packages are read/compile-time, while the
interpreter resolves against a live registry, so its defpackage products
join the runtime tier and may be renamed and deleted. A defpackage inside
another form (not top-level) registers its package when that form runs, also in
the runtime tier -- which the interpreter supports and the compiled backends
refuse, having no registry to register into.
A package keeps a member table: what intern,
export, import,
shadowing-import and
shadow put into it, and what
unintern takes out. find-symbol
answers nil for a name before it is interned and the symbol (with its
:internal / :external / :inherited status) after, use-package makes an
exported member inherited, and do-symbols /
with-package-iterator walk the table plus
what the use list brings in, every symbol spelled the way code spells it. A
symbol merely read in the source under a package is not recorded -- a
definition made under it counts, since a defun is an interning. On the
interpreter every package's table is live; on the compiled backends the
packages the program creates with make-package keep a live table while the
read/compile-time ones are frozen (the mutators answer t there without a
change).
Packages are resolved at read/compile time (in source order), so in-package is a top-level directive: which package a symbol in the source belongs to is decided by the in-package above it, not by a runtime setq of *package* (in compiled output the whole file is resolved before it runs; the interpreter resolves each top-level form as it reaches it, so a runtime assignment does affect the forms after it there). In compiled output a runtime-loaded file's package directives are not processed; the rontolisp package's functions (version, ...) are not available as first-class values (they cannot be passed to mapcar/funcall); and a cl symbol name must not be shadowed as a local variable inside a package that does not use cl.
rontolisp Package Extensions
The symbols the rontolisp package owns are implementation-specific and not
part of Common Lisp. They must be referenced with the rontolisp: qualifier
(or used unqualified after (in-package rontolisp)). Besides version,
the package provides asynchronous outgoing HTTP via rontolisp:fetch (which
returns a future) together with rontolisp:await (resolve) and
rontolisp:futurep (type predicate), and JSON conversion via
rontolisp:json-parse /
rontolisp:json-stringify
(JavaScript JSON.parse/JSON.stringify style). All of these have their own
pages in the Functions reference,
including the full rontolisp:fetch /
rontolisp:await /
rontolisp:futurep documentation.
Two members of the package are neither functions nor macros but read-time
literals: rontolisp:current-file and rontolisp:current-line, which the
reader replaces with the position they stand on. Because they are resolved
before any in-package directive is interpreted, they are the exception to the
rule above — they must always be written qualified. See
Source position literals.