Thread overview
Template argument deduction (not the implicit kind)
Jul 31, 2004
Andy Friesen
Jul 31, 2004
Sean Kelly
Jul 31, 2004
Andy Friesen
July 31, 2004
The current ML-ish pattern-matching style of templates is great, but currently has a few inconvenient limitations.

For instance, we can specialize a template for all arrays by doing

    template Templ(T : T[]) { ... }

Which specializes for all arrays.  The pattern is matched against the actual type supplied; this particular pattern matches all arrays, but only arrays.  The template argument T recieves the type of an element of this array type.

There are one relatively big thing we can't do, though:

We can't match more than one type from a single supplied type, or match part of a type without capturing it into an argument which would have to be explicitly specified anyway.

This makes it impossible, for instance, to specialize on associative arrays.  We can do

    template Templ(T : T[T]) { ... }

But this will only match an AA whose key and value types are identical.  The solution is somewhere along the lines of

    template Templ(Key, Value : Value[Key]) { ... }

There's a pretty big problem, though: we have to supply the key type along with the associative array type when we use it.  This is clumsier than just passing Key and Value explicitly, and so is effectively useless: we have no way to detect whether a type is an AA or not.


I don't know how much of a strain it would place on the template specialization system, but it would be great if these patterns could match on more than one template argument.

All that remains is to keep it clear just how many arguments are to be supplied when instantiating the template:

   // the pattern applies to a group, and not just one argument
   template Templ( (Key, Value) : Value[Key])

A second, perhaps simpler idea that comes to mind is a way to express a constraint without affecting the value that the template argument recieves.  For instance, we could do

    // null matches any type but does nothing with it; AA recieves the exact type passed
    template Templ(AA : null[null])

    // matches all AAs; the key type is captured
    template Templ(KeyType : null[KeyType])

    // capture the return type of a delegate that recieves exactly one argument of any type
    template Templ(ReturnType : ReturnType delegate(null))

    template Templ(T : null!(T)) // dare I hope?  Catch any template instantiation that recieved exactly one argument

 -- andy
July 31, 2004
Andy Friesen wrote:
> 
> We can't match more than one type from a single supplied type, or match part of a type without capturing it into an argument which would have to be explicitly specified anyway.
> 
> This makes it impossible, for instance, to specialize on associative arrays.  We can do
> 
>     template Templ(T : T[T]) { ... }
> 
> But this will only match an AA whose key and value types are identical.  The solution is somewhere along the lines of
> 
>     template Templ(Key, Value : Value[Key]) { ... }

I'd been meaning to try this out.  If it's not possible then it definately should be.  And by the syntax you describe.

I'd also like to have something like template template parameteres, though the syntax for these is a bit less clear.  Perhaps this?

template Templ( Key!(Value) ) {}

> All that remains is to keep it clear just how many arguments are to be supplied when instantiating the template:
> 
>    // the pattern applies to a group, and not just one argument
>    template Templ( (Key, Value) : Value[Key])

I'm not sure about this... how many arguments are supplied, 1 or 2?

>     // null matches any type but does nothing with it; AA recieves the exact type passed
>     template Templ(AA : null[null])
> 
>     // matches all AAs; the key type is captured
>     template Templ(KeyType : null[KeyType])

I like what you're getting at but Walter's probably the only one who can answer which syntax works best.  Any way you cut it though, we'll need to be able to do this type of stuff.


Sean
July 31, 2004
Sean Kelly wrote:

>> All that remains is to keep it clear just how many arguments are to be supplied when instantiating the template:
>>
>>    // the pattern applies to a group, and not just one argument
>>    template Templ( (Key, Value) : Value[Key])
> 
> 
> I'm not sure about this... how many arguments are supplied, 1 or 2?

One.  The rule would be that every group recieves exactly one argument from the caller.  For instance, something like this would demand four input arguments and produce six type arguments for use by the implementation:

    template ScaryPermutation(
        (LeftKey, LeftValue) : LeftKey[LeftValue],
        (RightKey, RightValue) : RightKey[RightValue],
        alias Comparer,
        ResultType : ResultType[]
    ) { ... }

Every group must have a specialization, and every element of a group must match at least one part of that specialization.

>>     // null matches any type but does nothing with it; AA recieves the exact type passed
>>     template Templ(AA : null[null])
>>
>>     // matches all AAs; the key type is captured
>>     template Templ(KeyType : null[KeyType])
> 
> 
> I like what you're getting at but Walter's probably the only one who can answer which syntax works best.  Any way you cut it though, we'll need to be able to do this type of stuff.

Right.  It's just a matter of what's easier to implement and use. :)

 -- andy