Implicit and Dynamic Parameters

Basic Ideas

If functions have very long parameter lists, and many of these parameters are simply passed down to nested function invocations, it is tempting to replace these parameters with global variables in order to shorten formal parameter and actual argument lists. Since the use of global variables is generally discouraged, however, a better solution is to use implicit parameters, which are part of a function's signature just like normal parameters, but which need not be passed explicitly in function calls. If an explicit argument value for an implicit parameter is missing in a call, an entity of the same name from the static calling context is used implicitly instead; if no such entity exists, or if it has an incompatible type, the call is rejected by the compiler. Therefore, in contrast to normal explicit parameters whose names are irrelevant for callers, the names of implicit parameters constitute an important part of a function's signature.

Alternatively, a concept similar to environment variables in operating systems can be used in combination with so-called dynamic parameters: If an explicit argument value for a dynamic parameter is missing in a call, an exported variable of the same name and type provided by the dynamic calling context is used implicitly if possible. If no such variable is found, the parameter's default value (which is mandatory for dynamic parameters) is used.

More Advanced Applications

Implicit and dynamic parameters are also useful for passing additional context information to overloaded operators, which by their very nature have a very limited number of explicit parameters (usually one for unary and two for binary operators). As an example, operators performing arbitrary precision floating point arithmetic might have additional implicit or dynamic parameters specifying the actually desired precision or the preferred rounding mode.

Another useful application of implicit parameters are generic functions such as min, max, and sort, which implicitly depend on other functions such as less_than or operator<. For example in C++:

    template <typename T>
    T min (T x, T y) {
        if (x < y) return x; // Requires operator< (T, T) !
        else return y;
    }
Such kinds of implicit dependencies can be made more explicit by declaring the required functions as implicit parameters, e. g.:
    template <typename T>
    T min (T x, T y, implicit bool operator< (T, T)) {
        if (x < y) return x; // Calls the operator< passed as implicit parameter.
        else return y;
    }
According to the general rule for resolving implicit parameters mentioned above, a function call such as min(a, b) is only accepted by the compiler, if the static calling context provides a definition of operator< that accepts parameters possessing the same type T as the arguments a and b. If such an operator definition is found, it is passed as an additional ``invisible'' parameter to min. This rather simple rule could replace the quite complex C++ rules about ``dependent name resolution'' in template functions. Furthermore, different calling contexts (e. g., different namespaces) might well contain different definitions (i. e., implementations) of operator< for the same type T, which can be passed as implicit parameters, while a C++ ``dependent name'' must refer to the same function in all invocation contexts of an instantiation of a template function for a particular type T.

Publication

[1] C. Heinlein: "Implicit and Dynamic Parameters in C++." In: D. Lightfoot, C. Szyperski (eds.): Modular Programming Languages (Joint Modular Languages Conference, JMLC 2006; Oxford, England, September 2006; Proceedings). Lecture Notes in Computer Science 4228, © Springer-Verlag, Berlin, 2006, 37-56.
Describes the ideas sketched above in more detail and illustrates them with various examples.


Christian Heinlein, 22.09.09