Dependency
Almost every program in this course has started with import Io::PrintLine;, and that import only works because the manifest lists Io as a dependency. This lesson looks at that list properly. There are two kinds of dependency — packages from the registry, and packages in a folder on your own disk — and this program uses both.
The [Dependencies] section
The lesson's Rux.toml ends with three lines:
[Dependencies]
Io = { Namespace = "Rux", Version = "*" }
Math = { Namespace = "Rux", Version = "*" }
Units = { Path = "Units" }
The key on the left of each line is the import name: the first segment of every import that reaches into that package. Io = … is what makes import Io::PrintLine; mean something. The inline table on the right says where the package comes from, and its shape decides which kind of dependency it is.
Registry dependencies
A registry dependency names a namespace and a version requirement. Io and Math are standard packages, published under the Rux namespace. They ship with the compiler, so they are already in the package cache on your machine; for any other registry package, rux install downloads a matching version into that cache once, and builds read it from there without going online again.
The requirement says which versions are acceptable:
| Requirement | Accepts |
|---|---|
* | any version — whichever is installed |
^0.1.0 | 0.1.x, but not 0.2.0 |
>=1.2.0, <2.0.0 | a range spelt out |
rux list shows what each line resolved to — here Resolved Rux/Io @ * to 0.1.0, the same for Math, and Path Units at 'Units'.
In Rux 0.4.0,
rux add Rux/Io does not work for the standard packages. Write their line into Rux.toml yourself, as every lesson in this course does: Io = { Namespace = "Rux", Version = "*" }.Path dependencies
A path dependency names a folder holding a Rux.toml, relative to this manifest. Here it is Units/, right beside Src/:
pub const KilometresPerMile: float64 = 1.609344;
pub func ToMiles(kilometres: float64) -> float64 {
return kilometres / KilometresPerMile;
}
Its source is compiled with the program, so an edit to Units/Src/Units.rux shows up on the next build, and nothing needs installing. The price is that a package with a path dependency cannot be published: the path means nothing on anyone else's machine.
Both kinds look the same in the code
Once declared, nothing in the source says where a package came from:
import Io::PrintLine;
import Math::{ Hypot, Round };
import Units::ToMiles;
flowchart LR
reg[("registry")] -- "`rux install`<br/>(once)" --> cache[("package cache<br/>`Io`, `Math`")]
cache -- "`Namespace` + `Version`" --> prog["Dependency<br/>`Src/Main.rux`"]
folder["`Units/`<br/>beside `Src/`"] -- "`Path`" --> prog
prog --> exe["`Dependency.exe`"]Hypot(3.0, 4.0) from Math is the length of the long side of a right triangle — five kilometres for three east and four north — and ToMiles from Units converts it. Round(… * 100.0) / 100.0 keeps two decimal places.
The program
The whole lesson is one package in the Examples repository. Its comments explain every step.
// A package names what it needs in the `[Dependencies]` section of its `Rux.toml`. Each line's key
// is the import name, the first segment of every `import` that reaches into that package. This
// program uses both kinds of dependency there are:
//
// Io = { Namespace = "Rux", Version = "*" }
// Math = { Namespace = "Rux", Version = "*" }
// Units = { Path = "Units" }
//
// A registry dependency names a namespace and a version requirement. `rux install` downloads a
// matching version into the package cache on this machine, and builds then read it from there,
// without going online again. `*` accepts any version; `^0.1.0` would accept 0.1.x but not 0.2.0,
// and `>=1.2.0, <2.0.0` spells a range out.
//
// A path dependency names a directory holding a `Rux.toml`, relative to this manifest. The source
// there is compiled with this program, edits to it are seen on the next build, and nothing needs
// installing. A package with a path dependency cannot be published, because the path means
// nothing on anyone else's machine.
//
// Once declared, the two kinds look the same in the code.
import Io::PrintLine;
import Math::{ Hypot, Round };
import Units::ToMiles;
func Main() -> int {
// Three kilometres east, then four north: how far from the start, as the crow flies?
let kilometres = Hypot(3.0, 4.0);
let miles = Round(ToMiles(kilometres) * 100.0) / 100.0;
PrintLine("straight line {} km", kilometres);
PrintLine("which is {} miles", miles);
return 0;
}
Run it
cd Examples/Packages/Dependency
rux run
straight line 5.0 km
which is 3.11 miles
Common mistakes
Try it yourself
- Change the requirement for
Mathto^0.1.0and runrux list. Does anything change in the build? - Add a
ToKilometresfunction toUnitsand use it to convert the roundedmilesback. Why is the answer not exactly 5.0? - The import name does not have to match the package's own name. Rename the line to
Distance = { Path = "Units", Package = "Units" }and change the import to match.
Learn more
- Dependencies — requirement syntax, the package cache and target-specific dependencies
rux installandrux listin the CLI reference- Math — the standard package this program borrows
HypotandRoundfrom - Workspace — several packages, with path dependencies between them, kept in one tree