Templates

The FreeBASIC Extended Library contains preprocessor APIs for the instantiation of templates, which are pieces of generic code in the form of user-defined macros.

One (typical) benefit of templates is that they can minimize code duplication. For example, say that there is some procedure, an algorithm, that iterates through a range of UByte elements in an array:

' Gets an iterator `it` to the first element in the range [first,last) for
'
which `*it = value` is true, or `last` if there is no such element.
function Find ( first as ubyte ptr, last as ubyte ptr, value as ubyte ) as byte ptr
   
do while first < last
       
if *first = value then exit do
        first
+= 1
    loop
   
return first
end function

An effective procedure, but it can only search through UByte element ranges. If there is suddenly a need for a procedure with the same behavior and that works with Integer element ranges, one option is to overload Find and define a second version:

' Gets an iterator `it` to the first element in the range [first,last) for
'
which `*it = value` is true, or `last` if there is no such element.
function Find overload ( first as ubyte ptr, last as ubyte ptr, value as ubyte ) as ubyte ptr
   
do while first < last
       
if *first = value then exit do
        first
+= 1
    loop
   
return first
end function

' Gets an iterator `it` to the first element in the range [first,last) for
'
which `*it = value` is true, or `last` if there is no such element.
function Find ( first as integer ptr, last as integer ptr, value as integer ) as integer ptr
   
do while first < last
       
if *first = value then exit do
        first
+= 1
    loop
   
return first
end function

Notice how much code (and documentation !) is duplicated in this scenario. The only difference is in the signatures, which specify either UByte orInteger parameter types. To extend the functionality of Find to include ranges of other element types, typically the same code must be duplicated for each one. This is where a template can come in handy:

# include once "ext/templates.bi"

' ElementType - the type of elements iterated through.
# macro Find_Define( __, ElementType )
:
    '
Gets an iterator `it` to the first element in the range [first,last) for
   
' which `*it = value` is true, or `last` if there is no such element.
    function Find overload ( first as fbext_TypeName(ElementType) ptr, _
                             last as fbext_TypeName(ElementType) ptr,  _
                             value as fbext_TypeName(ElementType)      _
    ) as fbext_TypeName(ElementType) ptr
   
        do while first < last
            if *first = value then exit do
            first += 1
        loop
        return first
   
    end function
:
# endmacro

fbext_Instantiate( Find, ((ubyte)) )
fbext_Instantiate( Find, ((integer)) )
fbext_Instantiate( Find, ((double)) )

The new code begins by including the ext/templates.bi, which contains all of the macros used in the template system. Next, a macro is defined called Find_Define which has two template parameters, the second of which is the type of elements that Find can iterate through, called ElementType.

In order to specify this type, the macro fbext_TypeName is used in the parameter list. This macro translates the value of ElementType into something that fbc can understand.

Finally, the procedure template Find is instantiated with fbext_Instantiate, a macro which takes as a first argument the name of the template, in this case, Find. The second argument is a sequence of template arguments; one or more values enclosed in parenthesis, that will be passed to Find_Define as template arguments. Here, the behavior of the last 3 lines is similar to,

Find_Define( __, (ubyte) )
Find_Define( __, (integer) )
Find_Define( __, (double) )

with some stuff done behind the scenes. Thus, 3 Find overloads are defined, each that iterates through a different type of element, and with only 1 procedure definition. The procedure description comment has remained the same throughout the refactoring to emphasize the fact that the behavior has remained constant as well.

Tags: