Modules and packages, 1 of 6
Several files
Split a program into files, mark what other files use as Public, and import files by their paths.
What you’ll build
In this tutorial you take a program that’s in one file and split it into three: one for its shapes, one for the text it prints about them, and the main file. Each file is a module, and a file sees another’s declarations only when it imports them.
One file
Here is the whole program in main.fb:
Import std.core
Struct Rect
Field Width: Float
Field Height: Float
Method Area(): Float => Width * Height
End Struct
Function Square(side: Float): Rect => Rect(side, side)
Function Describe(r: Rect): String => "{r.Width} by {r.Height}, area {r.Area()}"
Print(Describe(Rect(4, 3)))
Print(Describe(Square(2)))4 by 3, area 12 2 by 2, area 4
A file of its own
Move Rect and Square into shapes.fb, beside main.fb. Everything a file declares is
private to it unless it’s marked Public, so Rect, its fields, its Method, and Square all
become Public. Then main.fb imports the file by its path, Import "./shapes", without the
.fb.
Import std.core
Public Struct Rect
Public Field Width: Float
Public Field Height: Float
Public Method Area(): Float => Width * Height
End Struct
Public Function Square(side: Float): Rect => Rect(side, side)Import std.core
Import "./shapes"
Function Describe(r: Rect): String => "{r.Width} by {r.Height}, area {r.Area()}"
Print(Describe(Rect(4, 3)))
Print(Describe(Square(2)))4 by 3, area 12 2 by 2, area 4
Leave Public off Square, and main.fb can’t call it:
Import std.core
Public Struct Rect
Public Field Width: Float
Public Field Height: Float
Public Method Area(): Float => Width * Height
End Struct
Function Square(side: Float): Rect => Rect(side, side)Import std.core
Import "./shapes"
Print(Square(2).Area())Compiling main.fb main.fb:4:7: error: 'Square' is private to shapes.fb | 4 | Print(Square(2).Area()) | ^^^^^^ shapes.fb:10:10: note: declared here | 10 | Function Square(side: Float): Rect => Rect(side, side) | ------ error: couldn't build main.fb because of 1 error
fb run main.fb builds both files into one executable. Only the main file has top-level code,
the statements outside any declaration, which run when the program starts. The other files only
declare things, and a statement at the top level of shapes.fb is an error.
A folder
A quoted path can go into folders, with / between them, and back out with ... Move
Describe into text/report.fb. It needs Rect, so it imports shapes.fb from the folder
above its own.
Import std.core
Public Struct Rect
Public Field Width: Float
Public Field Height: Float
Public Method Area(): Float => Width * Height
End Struct
Public Function Square(side: Float): Rect => Rect(side, side)Import std.core
Import "../shapes"
Public Function Describe(r: Rect): String => "{r.Width} by {r.Height}, area {r.Area()}"Import std.core
Import "./shapes"
Import "./text/report"
Print(Describe(Rect(4, 3)))
Print(Describe(Square(2)))4 by 3, area 12 2 by 2, area 4
A path is always from the importing file’s folder. It can’t leave the folder the main file is in, so a program’s files all live under it. In a package, which project.toml makes, it’s the package’s folder.
Qualified names
An Import also brings a module’s names in under its last name, so shapes.Square and
report.Describe name the same things as Square and Describe. A qualified name tells two
modules’ declarations of one name apart. Here text/plain.fb has a Describe of its own:
Import std.core
Public Struct Rect
Public Field Width: Float
Public Field Height: Float
Public Method Area(): Float => Width * Height
End StructImport std.core
Import "../shapes"
Public Function Describe(r: Rect): String => "{r.Width} by {r.Height}, area {r.Area()}"Import std.core
Import "../shapes"
Public Function Describe(r: Rect): String => "a rectangle"Import std.core
Import "./shapes"
Import "./text/report"
Import "./text/plain"
Local room = Rect(4, 3)
Print(report.Describe(room))
Print(plain.Describe(room))4 by 3, area 12 a rectangle
An unqualified Describe(room) would fit both, and is an error that says “the call to
‘Describe’ is ambiguous”, with a note at each of them.
What you learned
- Each
.fbfile is a module, and what it declares is private to it unless it’sPublic. Import "./path"imports a file by its path from the importing file, without.fb.- Only the main file has top-level code; the other files declare things.
- An imported module’s names can be qualified by its last name, as
report.Describe.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.