Chapter 13's project needed nothing but a directory. Once it depends on code that lives
somewhere else, it gets a dawn.toml: an optional manifest for what the directory
convention cannot say, which is the project's identity and its dependencies. The layout,
the entry point and the module paths stay the directory's business, and a project
without one works exactly as before.
schema = 1 # always the first key
name = "myapp" # the project's identity, [a-z_][a-z0-9_]*
A dependency is a source package#
A package is a project of its own, with its own dawn.toml and its own src/. Here is a
small one, greet, sitting next to myapp:
greet/
├── dawn.toml # schema = 1, name = "greet", version = "1.0.0"
└── src/
├── hello.dawn
└── style.dawn
myapp/
├── dawn.toml
└── src/
└── main.dawn
greet/src/style.dawn:
# visible to every module of the greet package, and to nothing outside it
pub(pkg) fn shout(s: String) -> String = s ++ "!"
greet/src/hello.dawn:
use style.{shout}
pub fn hello(name: String) -> String = shout("hello, ${name}")
Inside the package, modules import each other by their path under the package's own
src/, as chapter 13's did. dawn add writes the dependency into myapp's manifest:
$ dawn add ../greet --dir myapp
Added greet as `greet` (path myapp/../greet)
schema = 1
name = "myapp"
[deps]
greet = "../greet"
The key under [deps] is how myapp spells the package: it is the first segment of a
use line.
myapp/src/main.dawn:
use greet/hello.{hello}
pub fn main() -> Unit !io = println(hello("Dawn"))
dawn run myapp prints hello, Dawn!.
pub(pkg): shared inside a package, hidden outside it#
Between module-private (nothing written) and pub there is a third level. A pub(pkg)
declaration is visible to every module of its own package, the unit one dawn.toml
describes, and to nothing outside it. shout is a helper the modules of greet share,
and myapp cannot reach it:
$ dawn run myapp # main.dawn now also says: use greet/style.{shout}
error: `shout` is package-private to package `greet`
--> myapp/src/main.dawn:2:18
|
2 | use greet/style.{shout}
| ^^^^^
= hint: only modules of package `greet` may name it
A pub declaration's signature may not mention a pub(pkg) type, by the same rule that
keeps a module-private type out of a public signature, and dawn doc lists pub items
only. A project with no dawn.toml is one package, and so is the bundled standard
library as a whole.
Remote packages, versions and MVS#
A path is for code that sits next to yours. A published package is an archive at a URL, pinned by the hash of what it unpacks to:
[deps.json]
url = "https://github.com/dawnop/dawn-lang/archive/refs/tags/v0.7.0.zip"
version = "1.0.0"
hash = "d1:<sha256>" # content hash of the unpacked file tree
subdir = "packages/json" # where the package sits inside the archive
Nobody computes that hash by hand. dawn add <url> fetches the archive, hashes it, reads
the package's own manifest for its name and version, and writes the entry, leaving the
comments and layout of the rest of the file as they were; --subdir says where the
package sits in the archive and --as picks a different key. Adding the same package
again updates its entry in place, which is how a version is bumped.
When two packages in one program depend on the same third one at different versions, the
program gets one copy of it: the highest of the minimum versions asked for. This is
minimal version selection (MVS), the algorithm Go uses, and a requirement is only ever a
minimum: no upper bounds, no exclusions. For Dawn the single copy is not a convenience.
Every trait-and-type pair has exactly one impl in a whole program (chapter 16), and two
copies of a package would be two copies of each of its types, with two impls each. A
package's identity is the name in its own manifest rather than the key you gave it,
so a major version that renames the package (json2) can still be spelled
use json/... by keeping the old key.
The third table, [java-deps], lists Maven coordinates for chapter 11's use java
(sqlite = "org.xerial:sqlite-jdbc:3.36.0.3", an exact version and nothing else). The
JVM toolchain resolves and fetches them; dawnc refuses use java and so has no use for
them. The design and its reasons are in package-design.md and
package-visibility-design.md, in Chinese.
See also: spec.en.md §10.1, §10.4