Skip to content
FutureBlitz

    Install

    Basics, 2 of 8

    Variables and constants

    Local, Const, and Global, what each can see, and why a variable has a value before it's read.

    What you’ll build

    A program that takes orders at a café: it counts them, keeps a running total, and prints a summary. It uses each of the three ways to declare a name, Local, Const, and Global, and shows the rules that catch mistakes with them before the program runs.

    Locals

    Local declares a variable. With a value, its type is the value’s; without one, the type is written after a colon. A variable keeps its type: it can be given a new value of that type, but not a value of another.

    cafe.fb
    Import std.core
    
    Local orders = 0
    Local total: Int = 0
    Local last: String
    
    orders += 1
    total += 350
    last = "espresso"
    orders += 1
    total += 425
    last = "cappuccino"
    Print("{orders} orders, {total} cents, the last a {last}")
    Output
    2 orders, 775 cents, the last a cappuccino

    Assigning "three" to orders would be an error, since orders is an Int. A name must be declared before it’s used, so a misspelled name is an error too, not a new variable.

    A value on every path

    A variable declared without a value must be assigned before it’s read, on every path the program can take to the read. Here size is assigned in both branches of the If, so the read after it is fine.

    cafe.fb
    Import std.core
    
    Local cents = 425
    Local size: String
    If cents > 400
        size = "large"
    Else
        size = "small"
    End If
    Print("a {size} order")
    Output
    a large order

    Without the Else, size has no value when cents is 400 or less, and the program doesn’t build. The check happens when the program is compiled, so a variable can never be read before it holds a value:

    cafe.fb
    Import std.core
    
    Local cents = 425
    Local size: String
    If cents > 400
        size = "large"
    End If
    Print("a {size} order")
    $ fb run cafe.fb
       Compiling cafe.fb
    cafe.fb:8:11: error: 'size' is read before it's assigned
      |
    8 | Print("a {size} order")
      |           ^^^^
    error: couldn't build cafe.fb because of 1 error

    Constants

    Const declares a value that never changes. Whenever its value can be worked out when the program is compiled, as these can, it is, and then it costs nothing when the program runs; one that needs the running program, like a call to a function that reads a file, is worked out once as the program starts, with the Globals. One known when the program is compiled can be used anywhere in its file, even above its declaration. These are written in UPPER_CASE, a common way to mark constants.

    cafe.fb
    Import std.core
    
    Const ESPRESSO = 350
    Const TAX_PERCENT = 8
    Const WITH_TAX = ESPRESSO + ESPRESSO * TAX_PERCENT / 100
    
    Print("an espresso is {ESPRESSO} cents, {WITH_TAX} with tax")
    Output
    an espresso is 350 cents, 378 with tax

    Assigning to a Const, as in ESPRESSO = 400, is an error.

    Globals

    A Local in a file’s top-level code belongs to that code alone, and functions can’t see it. A Global is a variable for the whole file, which every function in it can read and change. A Global without a value starts at its type’s zero: 0, 0.0, False, or "".

    cafe.fb
    Import std.core
    
    Const TAX_PERCENT = 8
    Global orders: Int
    Global total: Int
    
    Function Order(item: String, cents: Int)
        orders += 1
        total += cents
        Print("{item}: {cents} cents")
    End Function
    
    Order("espresso", 350)
    Order("cappuccino", 425)
    Order("croissant", 300)
    Print("{orders} orders, {total + total * TAX_PERCENT / 100} cents with tax")
    Output
    espresso: 350 cents
    cappuccino: 425 cents
    croissant: 300 cents
    3 orders, 1161 cents with tax

    Had orders been a Local, Order wouldn’t compile, since it couldn’t see orders. Keep Globals few: a function that takes what it needs as parameters is easier to follow.

    Blocks and names

    A Local declared inside a block, like an If or a loop, exists only in that block. A name can’t be declared again in a block nested in the one that declared it, in a function or in top-level code, and a function’s Local can’t reuse one of its parameters’ names, so one name always means one variable there.

    cafe.fb
    Import std.core
    
    Local prices = [350, 425, 300]
    Local expensive = 0
    For price In prices
        Local over = price - 400
        If over > 0 Then expensive += 1
    End For
    Print("{expensive} item over 400 cents")
    Output
    1 item over 400 cents

    over is a new variable on each pass of the loop, and can’t be used after End For. Declaring another Local over in a block inside the loop would be an error.

    What you learned

    • Local declares a variable; its type is its value’s, or written after a colon.
    • A variable keeps its type, and must be assigned on every path before it’s read.
    • Const is a value that never changes, worked out when the program is compiled whenever it can be.
    • Global is shared by a file’s functions, and starts at its type’s zero.
    • A Local lives in its block, and the blocks nested in that one can’t reuse its name.

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