Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Using Modules

As we have already seen, the use construct brings members of a module into local scope.

For example, given the program:

mod Paint {
    pub enum Color {
        case Red, Green, Blue
    }

    pub type alias Hue = Color

    pub def isWarm(c: Color): Bool =
        match c {
            case Color.Red    => true
            case Color.Green  => false
            case Color.Blue   => false
        }
}

All of the following uses are meaningful:

use Paint.Color
use Paint.Color.{Red, Green, Blue}
use Paint.Hue
use Paint.isWarm

All Kinds of Uses

Flix supports several kinds of uses, including:

  • A qualified use of a name: use Paint.Color.
  • A qualified use of multiple names: use Paint.Color.{Red, Green, Blue}.
  • A qualified use with rename: use Paint.{Color => Shade}.
  • A qualified use with multiple renames: use Paint.Color.{Red => R, Green => G, Blue => B}.

A rename is always written inside braces, even when we rename a single name.

Note: Flix does not support wildcard uses.

Note: A use must be qualified. We cannot write use Paint, and we do not have to: a top-level module, such as Paint or List, is always in scope.

Uses of a Package

A use can also reach a module of a Flix package that the project depends on. We write the mount of the package, the name it is declared under in flix.toml, followed by :::

use game::Board                          // a top-level module of the package
use game::Game.Rules                     // a nested module
use game::Game.Rules.players             // a function
use game::{Board, Game}                  // several modules
use game::Game.Rules.{players => count}  // with a rename

The :: separates the package from the module path inside it, and the module path is separated by . as always: we write use game::Game.Rules, never use game::Game::Rules. There must be no whitespace around the ::, and it can occur at most once in a use.

A use that names no package is unaffected: use Chain.Empty reaches the standard library, and use Paint.Color reaches our own module, exactly as before.

Note: The :: can be written in a use only. We cannot write game::Board.place() in an expression, nor game::Board in a type.

See Using Dependencies for how a package is mounted.

Where can Uses Occur?

Flix supports uses in three places:

  • At the top of a file.
  • Inside modules.
  • Inside functions.

A use at the top of a file, or inside a module, must be written before the declarations of that file or module.

For example:

mod A {
    use Chain.Empty
    use Chain.One
    use Chain.Chain
    use Int32.max

    pub def maxValue(c: Chain[Int32]): Int32 = 
        match c {
            case Empty       => 0
            case One(x)      => x
            case Chain(x, y) => max(maxValue(x), maxValue(y))
        }
}

which can also be written as:

mod A {
    pub def maxValue(c: Chain[Int32]): Int32 = 
        use Chain.Empty;
        use Chain.One;
        use Chain.Chain;
        use Int32.max;
        match c {
            case Empty       => 0
            case One(x)      => x
            case Chain(x, y) => max(maxValue(x), maxValue(y))
        }
}

Note the use of semicolons when inside an expression.

Default Uses

In Flix, a few built-in constructors are always in scope:

  • List.Nil and List.Cons.
  • Option.None and Option.Some.
  • Result.Ok and Result.Err.