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.
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)$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.
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)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 []=.
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])$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): Tdefines+for a type, and makes+=work too.- An Operator has no
Selfand 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.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.