Import statements make code from other libraries available in the current library. They must be at the top-level and at the top of the file (possibly following some comments).
An import always starts with the
import keyword, followed by identifier
segments that tell Toit how to find the library. Optionally it can be
suffixed by customizations:
Depending on whether the identifier segments start with a
. or not, the
import is a local or global import. Toit uses a different strategy to
locate the target file for each of these two strategies.
For local imports Toit searches for the target library relative to the current library.
For example, let's assume we have a file structure as follows:
. ├── my_lib │ ├── my_lib.toit │ ├── other.toit │ └── sub │ └── sub.toit └── sibling ├── sibling2.toit └── sibling.toit 3 directories, 5 files
If we are editing
my_lib.toit then we can import
sibling.toit as follows:
import .sub.sub and
import ..sibling.sibling could
be shortened to
import .sub and
import ..sibling respectively.
(See folder shortcut below).
. indicates that the import is a local import. Further
dots move up the folder hierarchy.
For locally imported libraries all their top-level elements are directly visible inside the importing library without any prefix. See customizations below for ways of changing that.
Global imports are importing libraries that come from packages or the SDK.
import math imports the mathematics library that is shipped
with the SDK.
The compiler has a mapping from identifier to location. The first identifier in the segment list is used to find a folder or file. After that, the local and global resolution works the same. That is, a global import can dot into sub-folders the same way as for local imports. A common use of dotting is for the JSON library which is a sub-folder of encodings:
Once imported, all global elements of the imported library are available
through a prefix. By default the prefix is the last identifier of the
segment list. In the case of the
encodings.json import above, the prefix
would thus be
json, and one could call
json.parse to call the
parse function of that library (toitdoc).
Note, that global imports also apply the folder shortcut, as described below.
It is very common to have a folder and a toit file with the same name. The Toit language thus has a shortcut to avoid repeating the last identifier twice: if an import would resolve to a folder, Toit looks for a Toit file that has the same name as the last segment.
For example, assume we have the following structure:
main.toit we can import
sub.toit by writing
As discussed, this is repetitive, so instead this can be shortened to:
The same mechanism applies to SDK or package imports. If the resolution of an import finds a folder, Toit tries to find a file with the same name as the last segment instead.
Say, we want to use the morse package.
When installing this package
toit pkg install github.com/toitware/toit-morse, the package manager
downloads the sources and adds a mapping from the package's name
the location it downloaded the sources. Specifically, the mapping points to
src folder of the package.
Here is the file hierarchy of the
When the Toit language now sees an
import morse it uses that mapping
to find the
src folder of the downloaded sources. Since, the target
is a folder, Toit now uses the last identifier (here there is just one:
morse) and search for
morse.toit in that folder.
By default a local import simply makes all top-level elements of the imported library visible (without prefix). Similarly, a global import provides the top-level elements through a prefix, which is the same as the last segment.
In some cases this simple approach is not convenient, and Toit allows to customize imports.
A developer can set the prefix of an import with the
show keyword selectively imports the specified top-level elements
and makes them available without prefix:
In the example, we only import the
cos functions from the
math library and make it available without any prefix.
For the local
.other import we restrict the import to one single
If we want to access all identifiers of the
math library without prefix
we can write
import math show *. The
show * clause just removes the
prefix and treats the global import the same as a local import.
Libraries can export elements from other libraries. Every exported element is visible as if it was a top-level element of the exporting library.
When this library is imported, the importee sees two entries:
print_hello. For example, let's say this library is imported locally
Here we import
export_example with a prefix
example. This gives access
to the elements
cos on this prefix.
Note that the main Toit file could also just import
math itself, but there
are often reasons why that's not as convenient. Most commonly,
used to provide a curated subset of a package.
Say we have the following package structure:
. └── src ├── feature1.toit ├── feature2.toit ├── feature3.toit └── my_package.toit 1 directory, 4 files
my_package.toit could be written as follows:
// We are the main-entry point for this package. // Provide the most common features. import .feature1 import .feature2 // Don't expose feature3 automatically. Users can // import it with `import my_package.feature3` if needed. // Export all identifiers. export *
show *, the
export * affects all identifiers, and
thus re-exports all elements that have been imported.
The IDE will not show identifiers that end with
_ if they come from a
different package. There is no strict enforcement of this privacy
mechanism, but developers should not use
identifier_ variables of
libraries that have been imported through a global import.