Skip to content
FutureBlitz

    Install

    Compile-time code, 1 of 4

    Consts and compile-time evaluation

    Have the compiler work out values before the program runs, with Consts, Const Functions, and

    What you’ll build

    A program whose numbers are worked out by the compiler: the seconds in a day and a week, a Fibonacci number from a Const Function, and the size of a fixed array. You’ll see which values the compiler computes, what happens when one of them overflows, and how #If picks code for a debug or a release build.

    Values the compiler works out

    Const declares a value that can’t change. An expression made only of literals, Consts, operators, and casts is computed by the compiler, so the program holds the result and does no arithmetic for it when it runs.

    Import std.core
    
    Const SECONDS_PER_DAY = 24 * 60 * 60
    Const SECONDS_PER_WEEK = SECONDS_PER_DAY * 7
    
    Print(SECONDS_PER_DAY, SECONDS_PER_WEEK)
    Output
    86400 604800

    Assigning to a Const is an error: 'SECONDS_PER_DAY' is a Const and can't be changed. A Const whose value needs the program to run, like one that calls an ordinary function, is still a Const, but it’s worked out once, as the program starts, in order with the Globals. A top-level Const the compiler works out can be used anywhere in its file, even above its own line.

    Const Functions

    A Const Function runs in the compiler whenever every argument it’s given is known at compile time. It takes and gives numbers, Bools, Strings, Chars, and Enums, can’t throw, and calls only other Const Functions, Assert, Panic, and the New a Struct gets. It uses no Globals, and makes no objects or arrays, though its Locals can be Structs, tuples, and fixed arrays.

    Import std.core
    
    Const Function Fib(n: Int): Int
        Return n < 2 ? n : Fib(n - 1) + Fib(n - 2)
    End Function
    
    Const Function IsPrime(n: Int): Bool
        If n < 2 Then Return False
        Local d = 2
        While d * d <= n
            If n % d == 0 Then Return False
            d += 1
        End While
        Return True
    End Function
    
    Const FIB_20 = Fib(20)
    Print(FIB_20)
    Print(IsPrime(97), IsPrime(91))
    
    Local n = 30
    Print(Fib(n))
    Output
    6765
    True False
    832040

    Fib(20) and both calls of IsPrime are worked out as the program is built. Fib(n) takes a Local, which isn’t known until the program runs, so it’s an ordinary call, made when the program runs.

    Sizes known at compile time

    A fixed array’s size, like the 5 in Int[5], has to be known at compile time. A Const, or a Const Function’s result, can give it.

    Import std.core
    
    Const Function Fib(n: Int): Int
        Return n < 2 ? n : Fib(n - 1) + Fib(n - 2)
    End Function
    
    Const SLOTS = Fib(10)
    
    Struct Board
        Field Cells: Int[SLOTS]
    End Struct
    
    Local board = Board()
    board.Cells[0] = 7
    Print(board.Cells.Count, board.Cells[0])
    Output
    55 7

    A Const whose value is only known when the program runs, like one that calls an ordinary function, can’t be a size:

    Import std.core
    
    Function Levels(): Int => 3
    
    Const LEVELS = Levels()
    
    Struct Board
        Field Cells: Int[LEVELS]
    End Struct
    
    Print(Board().Cells.Count)
    $ fb run main.fb
       Compiling main.fb
    main.fb:8:22: error: a fixed array's size must be an integer known at compile time, like 64 or 8 * 8
      |
    8 |     Field Cells: Int[LEVELS]
      |                      ^^^^^^
    error: couldn't build main.fb because of 1 error

    Mistakes found at compile time

    What would panic when the program runs is an error when the compiler runs it: an overflow, a division by zero, an index out of range, or a failed Assert. The error points at the call and, in a note, at the line in the Const Function where it went wrong.

    Import std.core
    
    Const Function Fact(n: Int): Int
        Return n <= 1 ? 1 : n * Fact(n - 1)
    End Function
    
    Const BIG = Fact(25)
    Print(BIG)
    $ fb run main.fb
       Compiling main.fb
    main.fb:7:13: error: 'Fact' can't run at compile time: the result of '*' overflows Int32
      |
    7 | Const BIG = Fact(25)
      |             ^^^^^^^^
    main.fb:4:25: note: here
      |
    4 |     Return n <= 1 ? 1 : n * Fact(n - 1)
      |                         ---------------
    error: couldn't build main.fb because of 1 error

    Code for one build

    #If lines pick which code is compiled at all. DEBUG is defined in a debug build, RELEASE in one made with fb build --release, and PLATFORM_WINDOWS, PLATFORM_LINUX, or PLATFORM_MACOS by the platform it’s built on. The branches that aren’t picked are skipped, and don’t even need to parse.

    Import std.core
    
    #If DEBUG
    Print("a debug build")
    #Else
    Print("a release build")
    #End If
    Output
    a debug build

    The platform symbols work the same way. Built on Windows, this program prints its first line, and built on macOS or Linux, its second:

    Import std.core
    
    #If PLATFORM_WINDOWS
    Print("built on Windows")
    #ElseIf PLATFORM_MACOS || PLATFORM_LINUX
    Print("built on macOS or Linux")
    #End If

    What you learned

    • A Const made of literals, Consts, and operators is computed by the compiler.
    • A Const Function runs in the compiler when all its arguments are known, and as an ordinary call otherwise.
    • Fixed array sizes need values known at compile time, which Consts and Const Functions give.
    • A Const Function’s overflow or failed Assert at compile time is a compile error.
    • #If compiles code only for the builds and platforms it names.

    Report an issue with this page or with FutureBlitz on GitHub.