Skip to content
FutureBlitz

    Install

    Your own types, 7 of 8

    Operators on your own types

    Define +, -, ==, <, and indexing for your own types, so they read like built-in ones.

    What you’ll build

    A Money type that adds, subtracts, multiplies, and compares like a number, while keeping its amount in whole cents so it never rounds. Then a Ledger whose entries are read and written with brackets, like an array’s.

    Arithmetic

    An Operator declaration defines what an operator does for a type. It’s written inside the type, takes its operands as parameters, at least one of them of the type, and has no Self. The indexing Operators, at the end of this page, are the exception. Unary - takes one parameter.

    money.fb
    Import std.core
    
    Struct Money Implements Printable
        Field Cents: Long
    
        Operator +(a: Money, b: Money): Money => Money(a.Cents + b.Cents)
        Operator -(a: Money, b: Money): Money => Money(a.Cents - b.Cents)
        Operator -(a: Money): Money => Money(-a.Cents)
        Operator *(a: Money, times: Int): Money => Money(a.Cents * times)
    
        Method ToString(): String
            Local sign = Cents < 0 ? "-" : ""
            Local whole = Cents < 0 ? -Cents : Cents
            Return "{sign}${whole / 100}.{whole % 100:02}"
        End Method
    End Struct
    
    Local price = Money(1250)
    Local tax = Money(100)
    Print(price + tax, price * 3, -price, tax - price)
    
    Local total = Money(0)
    total += price
    total += tax
    Print(total)
    Output
    $13.50 $37.50 -$12.50 -$11.50
    $13.50

    += works once + does: total += price is total = total + price.

    Comparing

    A Struct’s == compares its fields already, and a Class’s compares identity. An Operator == replaces that, and != is always its opposite. Operator < orders values; with Comparable, as Interfaces shows, it gives >, <=, and >= too.

    money.fb
    Import std.core
    
    Struct Money Implements Comparable
        Field Cents: Long
    
        Operator <(a: Money, b: Money): Bool => a.Cents < b.Cents
    End Struct
    
    Local small = Money(250)
    Local large = Money(1000)
    Print(small < large, small > large, small <= Money(250))
    Print(small == Money(250), small != large)
    Output
    True False True
    True True

    Indexing

    Operator [] reads an element by index, and Operator []= sets one, with its value as the last parameter. Unlike the other Operators, they run on an object, as Methods do, so they use its fields by name. Indexing with += reads through [], then writes through []=.

    ledger.fb
    Import std.core
    
    Struct Money Implements Printable
        Field Cents: Long
    
        Operator +(a: Money, b: Money): Money => Money(a.Cents + b.Cents)
        Method ToString(): String => "${Cents / 100}.{Cents % 100:02}"
    End Struct
    
    Class Ledger
        Field entries: Money[] = []
    
        Method Add(amount: Money)
            entries.Add(amount)
        End Method
    
        Operator [](index: Int): Money => entries[index]
    
        Operator []=(index: Int, value: Money)
            entries[index] = value
        End Operator
    End Class
    
    Local ledger = Ledger()
    ledger.Add(Money(1250))
    ledger.Add(Money(800))
    ledger[1] = Money(850)
    ledger[0] += Money(100)
    Print(ledger[0], ledger[1])
    Output
    $13.50 $8.50

    An index can be several values, as in grid[x, y], with a parameter for each.

    What you learned

    • Operator +(a: T, b: T): T defines + for a type, and makes += work too.
    • An Operator has no Self and takes a value of its type, except [] and []=, which run on the object.
    • Operator == replaces the default ==, and != is always its opposite.
    • Operator [] and []= make a type indexable, with one index or several.

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