UsingExtTemplates

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 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 &lt; last        if *first = value then exit do        first += 1    loop    return first end function

An effective procedure, but it can only search through element ranges. If there is suddenly a need for a procedure with the same behavior and that works with element ranges, one option is to overload  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 &lt; 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 &lt; 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 or parameter types. To extend the functionality of 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: ' ElementType - the type of elements iterated through. ' 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 &lt; 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))
 * 1) include once "ext/templates.bi"
 * 1) macro Find_Define( __, ElementType ):

The new code begins by including the template header, which contains all of the macros used in the template system. Next, a macro is defined called which has two template parameters, the second of which is the type of elements that can iterate through, called. In order to specify this type, the macro is used in the parameter list. This macro translates the value of into something that  can understand.

Finally, the procedure template 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 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.