In Odin we have the concept of packages
. A package
is a directory that contains different files. Directories are important to Odin
. Package names must be unique and be a valid identifier. Example My_Package
.
package/
- file1.odin
- file2.odin
Is like the compiler concatenates all the files in a single file for a package.
Similar to this:
$ cat cat/paws.odin cat/meows.odin > cat/amalgamated_package.odin
All the files in the same package will share the package name in the file.
Example
cat/paws.odin
:package Cat
.cat/meows.odin
:package Cat
.
For using the public procedures, constants, structs, unions from a package we have to import it. Keep in mind that we import the directory as a whole and not a single file.
import "lib/cat"
We can make an alias
by using another name before the route.
import Cat "../cat"
Cat.meow()
Cat.sleep()
Aliases are needed if your package has an invalid identifier. For example if you store a library inside a version number.
0.4/
- mylib.odin
If we would like to import it we need an alias
.
import mylib "0.4"
Collections
Odin has the concept of collections
that are predefined paths that can be used in imports.
core:
The most common collection that contains useful libraries from Odin core likefmt
orstrings
.
You can define your own collection at build time
The following will define the collection project
and put the path at the current directory.
$ odin run . -collection:project=.
import "project:lib/cat"
Package Exports
Odin Exported Names are public by default (anything you declare in a file is public and can be accesed by other packages). If you don’t want to export something you have to use @(private)
before declaration.
@(private)
my_variable: int // cannot be accessed outside this package
@(private)
is equivalent to @(private="package")
.
You can make the declarations private by file, only available within the file where was declared.
@(private="file")
my_variable: int // cannot be accessed outside this file
Another option is using the #+private
or #+private file
general attributes before the package name. That makes all the file private by default and only available to the package or file itself.
private_by_default.odin
#+private
package Package1
// This procedure will only be available to the package
// impossible to make it public unless is stored in another file
// without the #+private directive
private_proc :: proc() -> int {
return 42
}
By using this alternative we can have a file that is only for storing private procedures and other data structures.
Being private by default is a benefit because it requires you to explicitly expose things to be part of your libraries API, improving the organization of your package.
my_package/
- api.odin // Public exports
- api.priv.odin // Package only exports
We can store all the private declarations in a single private file and not clutter with @(private)
in every symbol.
Package naming convention
The files and directory inside the package can be named with any valid operating system identifier name. And the package name could be different from the directory name. There is no official convention or standard for naming packages and files. The only requirement is that package names must be unique and be a valid Odin identifier.
Howerer these are some recommendations.
Directory Names
Use CamelCase
for directory names. This way our packages can be seen as “modules” that exports procedures, constants, structs and unions.
import "lib/Cat"
Cat.meow()
A package can internally use multiple packages and procedures, but we never interact with those internal packages directly. We name the directory Cat
because it exposes and groups all of the feline functionality.
By giving packages that expose and group related functionality CamelCase
naming, we help developers identify these patterns.
Package Identifier
Use Ada_Case
for package identifiers. Package identifiers must be a valid Odin identifier and be unique within the project. They do not need to follow the directory structure.
Example
Our Cat
package can be stored in lib/animals/Cat
but we don’t need to follow the directory tree for naming the package, as long as is unique it would be fine.
package Cat
Note: The core Odin library does use another convention using snake_case
(preferred a single word) for package names. Use the convention that most fits your taste and needs.
The idea is to be consistent in our project
Files
Files can be named with any operating system valid identifier.
Here are some recommendations:
- use
lowercase
for file names. - the main file must be named as the directory in lowercase. Eg.
animals/Cat/cat.odin
- use
dot (.)
for separating exports scopes. Eg.api.odin
,api.priv.odin
. - use
underscore (_)
for separating long filenames.my_great_api.odin
- functional postfixes also use underscore
only_linux.odin
,only_amd64.odin
. For procedures and other symbols that are exclusive to that target. The naming convention would beonly_<target>
. Example:api.priv.only_linux.odin