Overview

MUFL is a type-safe language, however, it must often handle data of a type that is not known in advance. A generic module is different from a non-generic one in that it can take type arguments, giving a generic module the ability to operate on many types using the same code.

For example, if you want to write a function that performs a linear search into an array, it could look something like:

module array_functions { 
    fn search (arr: any[], value: any) -> int { 
        sc arr -- (i->val)??val == value { 
            return i. 
        }

        return (-1). 
    }
}

This implementation is not type safe. A call to array_functions::search [1,2,3,4] "hello" scans the entire array and always returns -1. But in practice, the implementation should indicate that a programmer has made a mistake. A better implementation is to use a generic module:

generic module array_functions takes value_type { 
    fn search (arr: value_type[], value:value_type) -> int { 
        sc arr -- (i->val)??val == value { 
            return i. 
        }

        return (-1). 
    }
}

In this case, calling the function search with an array of one type and a search value of another type results in a compile-time error, saving programming time and effort.

Defining Generic Modules

Generic modules can be defined in applications, libraries, and their nested modules, as well as other generic modules.

The syntax is:

generic module [name] takes [list-of-types] {
    [code]
}

Generic Module Instances

In order to use functions and variables from a generic module, you must instantiate it with a specific set of type parameters. So the example above, in full, looks like:

module x {   
    generic module array_functions takes value_type { 
        fn search (arr: value_type[], value:value_type) -> int { 
            scan arr bind i has val where val == value { 
                return i. 
            }

            return (-1). 
        }
    }  
}

module y { 
    module int_array_functions instantiates x::array_functions with int. 
    int_array_functions::search [1,2,3,4] "hello". // compile error because hello fails the type check
    modue str_array_functions instantiates x::array_functions with str. 
    int_array_functions::search ["a", "b", "c"] "c". // ok
}

Instantiating generic modules inline is not currently possible. That is, there is no syntax to achieve something like: x::array_functions<int>::search