Is there a programming language where types can be parametrized by values?

Viewed 430

Parametrized types such as C++ templates are a nice thing, but most of the time they can only be parametrized by other types.

However, there is a special case in C++ where it is possible to parametrize a template by an integer. For example, fixed-length arrays are a typical use case:

template<typename T, int SIZE> class FixedArray 
{ 
    T m_values[SIZE]; 

public: 
    int getElementCount() const { return SIZE; }

    T operator[] (int i) const { 
        if (i<0 || i>=SIZE) 
            throw;
        else 
            return m_values[i]; 
    }  
};

void f()
{
    FixedArray<float, 5> float_array; // Declares a fixed array of 5 floats. 
    //The size is known at compile time, and values are allocated on the stack.
}

Only constant integers and pointers are allowed in C++, but I think it could be interesting to use any value for parametrization (floats, class instances, etc.). This could allow expressing preconditions at compile-time (usually informally specified in the documentation), and check them automatically at runtime. For example, here is an "Interval" template in an hypothetical C++ dialect :

// Interval of type T between TMin and TMax. 
template<typename T, T TMin, T TMax> class Interval
{
    T m_value;

public:
    Interval(int val) { *this = val; }

    Interval& operator = (T val) { 
        //check that 'val is in [TMin, TMax] and set the value if so, throw error if not
        if (val < TMin || val > TMax) 
            throw;
        else
            m_value = val; 

        return *this;
    };  

    operator T() const { return m_value; }
}   

// Now define a f function which is only allowing a float between O and 1
// Usually, that kind of function is taking a float parameter with the doc saying "the float is in 0-1 range". But with our Interval template we have
// that constraint expressed in the type directly.
float f(Interval<float, 0, 1> bounded_value)
{
    // No need to check for boundaries here, since the template asserts at compile-time that the interval is valid
    return ...;
}

// Example usage
void main();
{
    float val = 0.5;

    Interval<float, 0, 1> sample_interval = val;    // OK. The boundary check is done once at runtime.

    f(sample_interval);             // OK. No check, because it is asserted by the type constraint at compile-time.
                                // This can prevent endless precondition testing within an algorithm always using the same interval

    sample_interval = 3*val;            // Exception at runtime because the constraint is no longer satisfied

    f(sample_interval);             // If I am here, I am sure that the interval is valid. But it is not the case in that example.
}   

What could be interesting then would be to express relationships between these types. For example, expressing the rule to assign an Interval A to another Interval B with other boundaries, or simply a rule to assign a value to an Interval, with everything checked at compile-time.

Is there any language with this kind of parametrization (or a similar approach), or one must still be invented? Any useful research papers?

3 Answers
Related