12 Files and libraries
Use include to split one workflow across local files. Use import to reuse a versioned library from another Git repository. A ScienceLogo library is one Git repository with a main branch and a library.rkt file at its root. Importing makes its procedures and record interfaces available.
The Racket implementation requires the Git executable on PATH to resolve library imports. Included workflow files do not use Git.
12.1 Split one workflow across files
Every included file begins with #lang sciencelogo. Its path starts at the directory of the file containing include. An included workflow file has no workflow title or import and can include more files. For example, these three files are loaded from method.rkt:
method.rkt:
#lang sciencelogo |
workflow "Pendulum trial" |
include "methods/period.rkt" |
do period 20 10 as seconds-per-swing |
print seconds-per-swing |
methods/period.rkt:
#lang sciencelogo |
include "../shared/divide.rkt" |
to period :seconds :swings [ |
do divide :seconds :swings as result |
output result |
] |
shared/divide.rkt:
#lang sciencelogo |
to divide :total :count [output :total / :count] |
The reader assembles and validates the workflow before running it. Missing files, duplicate includes, and cycles are errors. include does not create a local scope.
12.2 Library syntax
Form | Rule |
library name language "0.2" [ ... ] | One declaration in the root library.rkt file; contains imports, includes, procedures, and record interfaces. The language version is optional |
import "Git URL" at "tag or commit" as alias | Directly in a library block, or at the top of an entry workflow |
include "relative/path.rkt" | Loads a file relative to the file containing this include |
do alias.procedure ... | Calls an imported procedure |
alias.Interface | Names an imported interface in construction, inheritance, is tests, and implement mappings |
The URL begins with https:// or file://. at selects a tag or full commit ID reachable from the library’s main branch, not a branch name. An alias is local to the file that declares the import. A library may import another library; a workflow imports that dependency itself if it needs to use the dependency’s procedures or interfaces directly. Importing a library never runs its procedures.
12.3 Make a small library
Create a separate directory named hello-world. Save this as its library.rkt:
#lang sciencelogo |
; @doc url: https://example.org/hello-world/ |
|
library hello-world language "0.2" [ |
to greeting [output "Hello, world!"] |
] |
The greeting procedure returns text. Loading the library does not print it. The optional comment line tells documentation tools where the library’s own documentation is published; see Link to a library’s documentation. The optional language "0.2" states the language version the library was written for; see State the language version. In that directory, initialize and tag the Git repository:
git init --initial-branch=main |
git add library.rkt |
git -c user.name="ScienceLogo example" -c user.email="example@example.invalid" commit -m "Add greeting library" |
git tag v1.0.0 |
12.4 Import and call it
Save the following investigation in another file. Replace the example file:// URL with the absolute path to your hello-world directory:
Compact
#lang sciencelogo |
|
workflow "Try a library" |
import "file:///absolute/path/to/hello-world" at "v1.0.0" as hello |
do hello.greeting as message |
print message |
Verbose
#lang sciencelogo |
|
workflow "Try a library" |
import library from "file:///absolute/path/to/hello-world" at "v1.0.0" as hello |
do hello.greeting as message |
print message |
The at value selects a tag or full commit ID reachable from main; it does not select a branch. hello is the local alias for this import. The call returns "Hello, world!" as message, and the investigation displays it. The reader resolves and validates the library before running the investigation.
12.5 State the language version
A library can state the ScienceLogo language version it was written and checked with, after its name, as in library hello-world language "0.2" [ ... ]. The version is a two-part number. The statement is optional, and it is not a limit: the reader loads the library under any language version. If the library fails to load under another version, the error also names the stated version and the version the reader implements. The workflow model keeps the stated version with each import as import-model-language. The library’s own tags, such as v1.0.0, are separate from the language version.
12.6 Link to a library’s documentation
A @doc url: marker in a comment at the top of library.rkt, after #lang sciencelogo and before the library form, gives the address of the library’s published documentation. A marker has the form @doc key: value in a ; or #| ... |# comment. Only url is used so far, with an http or https address. The ScienceLogo Documenter reads it and links a workflow’s documentation to those pages instead of generating them again. If a key appears more than once, the first marker is used and the Documenter warns.
The marker is a convention for tools, not ScienceLogo syntax. The reader ignores comments, so the marker does not change the library, its checks, or the workflow model. A library without it remains valid.
12.7 Share a record interface
A library can also define a data interface, with required fields and defaults grouped inside must [...]; see Records and interfaces. In library.rkt:
Compact
#lang sciencelogo |
|
library timing [ |
interface Timing [must [duration unit = "seconds"]] |
] |
Verbose
#lang sciencelogo |
|
library timing [ |
interface Timing [must [duration set unit to "seconds"]] |
] |
After committing and tagging that repository, a workflow can import and use it:
Compact
import "file:///absolute/path/to/timing" at "v1.0.0" as timing |
interface Timed-place [extends timing.Timing must [place]] |
trial = Timed-place.[duration = 2 place = "lab"] |
trial implement timing.Timing |
Verbose
import library from "file:///absolute/path/to/timing" at "v1.0.0" as timing |
interface Timed-place [extends timing.Timing must [place]] |
set trial to Timed-place with [set duration to 2 set place to "lab"] |
trial implements timing.Timing |
The alias qualifies the interface name just as it qualifies a procedure name. Interfaces may also be placed in included library files. An included file can use include "../shared/file.rkt" from a subdirectory: the path starts at the directory containing that include, and must stay in the same repository.
For larger libraries, the root library.rkt can contain include "relative/path.rkt" declarations and imports of other libraries. Included files contain top-level to, record interface, and include declarations. A dependency alias stays inside the library that declared it; a workflow imports that dependency separately if it needs to use its procedures or interfaces directly. The library specification has the full layout and dependency rules.