Operator overloading
A type that behaves like a number reads best when it is written like one:
half + third rather than half.Plus( third ). An operator overload is a
procedure the compiler calls when it sees an operator applied to your type.
function Gcd( byval a as int64, byval b as int64 ) as int64
a = abs( a ) : b = abs( b )
do while b <> 0
dim as int64 t = a mod b
a = b : b = t
loop
return a
end function
type Fraction
declare constructor( byval n as int64 = 0, byval d as int64 = 1 )
declare operator let( byval whole as int64 ) '' members: they change
declare operator +=( byref o as Fraction ) '' or convert this
declare operator cast( ) as ustring '' object
num as int64
den as int64
end type
constructor Fraction( byval n as int64, byval d as int64 )
dim as int64 g = Gcd( n, d )
if d < 0 then g = -g '' keep the sign on top
num = n \ g : den = d \ g
end constructor
operator Fraction.let( byval whole as int64 )
num = whole : den = 1
end operator
operator Fraction.cast( ) as ustring
if den = 1 then return str( num )
return num & "/" & den
end operator
'' Binary operators are global: neither side is privileged.
operator + ( byref a as Fraction, byref b as Fraction ) as Fraction
return Fraction( a.num * b.den + b.num * a.den, a.den * b.den )
end operator
operator * ( byref a as Fraction, byref b as Fraction ) as Fraction
return Fraction( a.num * b.num, a.den * b.den )
end operator
operator - ( byref a as Fraction ) as Fraction '' unary minus
return Fraction( -a.num, a.den )
end operator
operator = ( byref a as Fraction, byref b as Fraction ) as boolean
return a.num = b.num andalso a.den = b.den
end operator
operator <> ( byref a as Fraction, byref b as Fraction ) as boolean
return not ( a = b )
end operator
operator < ( byref a as Fraction, byref b as Fraction ) as boolean
return a.num * b.den < b.num * a.den
end operator
operator Fraction.+=( byref o as Fraction )
this = Fraction( num * o.den + o.num * den, den * o.den )
end operator
dim as Fraction half = Fraction( 1, 2 ), third = Fraction( 1, 3 )
print "1/2 + 1/3 = "; half + third
print "1/2 * 1/3 = "; half * third
print "-(1/2) = "; -half
print "2/4 = 1/2: "; Fraction( 2, 4 ) = half
print "1/3 < 1/2: "; third < half; ", 1/3 <> 1/2: "; third <> half
print "1/2 + 1/3 * 1/2 = "; half + third * half; " (* first)"
dim as Fraction total
total = 3 '' operator let, from an int64
total += half
total += Fraction( 6, -4 )
print "3 + 1/2 - 3/2 = "; total
Output
1/2 + 1/3 = 5/6
1/2 * 1/3 = 1/6
-(1/2) = -1/2
2/4 = 1/2: true
1/3 < 1/2: true, 1/3 <> 1/2: true
1/2 + 1/3 * 1/2 = 2/3 (* first)
3 + 1/2 - 3/2 = 2
An operator is defined like a function whose name is the operator:
operator + ( byref a as Fraction, byref b as Fraction ) as Fraction. From
then on, a + b on two fractions is a call to it.
Where an operator is declared depends on what it acts on:
| Operators | Declared | Why |
|---|---|---|
+ - * /, =, <>, <, unary -, ... | outside the type | neither operand is privileged |
let, += and the other compound assignments, cast | inside the type | they change, or convert from, this object |
[] | inside the type | see Indexing |
Declaring a binary operator inside the type is refused with
TKO0790: operator '+' cannot be a member of a type.
A few things in the example are deliberate:
- Each comparison is its own operator. Defining
=does not define<>, so<>is written asnot ( a = b )to keep the two in agreement. - Precedence does not change.
half + third * halfmultiplies first, because the expression is parsed before any operator procedure is chosen. operator let( byval whole as int64 )makestotal = 3work: it is assignment from another type. Assignment from anotherFractionis the ordinary copy, covered in Copying.operator cast( ) as ustringis what letsprintshow a fraction, as on the Display page.
A global operator sees only the type's public members, like any other code outside the type. That keeps operators from breaking the type's rules.
Inside a method, this cannot yet be an operand of an overloaded operator:
this = this + o is refused with TKO0820: no operator '+' takes these operand types. Build the result from the fields, as += does here, or copy
this into a local first.
Activities
- Add
operator -for two fractions, andoperator >. - Add
operator cast( ) as float64and printcast( float64, third ).