Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

What a type parameter asks for

( of T ) does not say what T can do. The compiler therefore checks a generic's body once for each type it is used with, against that real type. If the body uses an operator the type does not have, that instantiation fails.

'' Largest( of T ) uses '>' on T, but nothing in its header says so.
function Largest( of T )( items() as T ) as T
    var best = items( lbound( items ) )
    for each x in items
        if x > best then best = x
    next
    return best
end function

type Version
    as int32 major, minor
end type

dim releases( 0 to 2 ) as Version = { ( 1, 4 ), ( 2, 0 ), ( 1, 9 ) }
var newest = Largest( releases() )      '' Version has no '>'
print newest.major; newest.minor

Version has no >, so this does not build:

needsgt.tiko(5,14): error TKO0720: no operator > compares this type
     |
   5 |         if x > best then best = x
     |              ^
needsgt.tiko(15,21): note: in instantiation of 'largest( of version )'
     |
  15 | var newest = Largest( releases() )      '' Version has no '>'
     |                     ^

The error points at the generic's body, which is correct code. The cause is in the note: under it: line 15 asked for Largest( of Version ). Read an error from a generic to the end before you edit anything.

The fix is on the type's side: give Version the operator the generic uses.

'' Largest( of T ) needs '>' on T.
function Largest( of T )( items() as T ) as T
    var best = items( lbound( items ) )
    for each x in items
        if x > best then best = x
    next
    return best
end function

type Version
    as int32 major, minor
end type

'' Supply the operator the generic asks for.
operator > ( byref a as Version, byref b as Version ) as boolean
    if a.major <> b.major then return a.major > b.major
    return a.minor > b.minor
end operator

dim releases( 0 to 2 ) as Version = { ( 1, 4 ), ( 2, 0 ), ( 1, 9 ) }
var newest = Largest( releases() )
print "newest:"; newest.major; "."; str( newest.minor )

dim scores( 0 to 3 ) as int32 = { 70, 85, 90, 62 }
print "best score:"; Largest( scores() )

Output

newest: 2.0
best score: 90

Largest did not change. The same generic serves int32, which has > built in, and Version, which now has one of its own. Because a generic's demands are not written in its header, state them in a comment above it, as this one does.

Activities

  1. Write a generic Contains( of T )( items() as T, byval x as T ) and use it with Version. Which operator does it need?
  2. Remove the > operator and add a < instead. Does the error change?