August 21, 2002
In article <ak0rom$app$3@digitaldaemon.com>, Walter says...
>"Mac Reiter" <Mac_member@pathlink.com> wrote in message news:ak09pv$1b4k$1@digitaldaemon.com...
>> 3. It might be useful to have some way to say that some template
>parameters are
>> "like" or "derived from" other template parameters:
>>
>> template Cage(Base, Derived like Base) {/*whatever*/}
>>
>> Then at instantiation:
>>
>> inst Cage(Bird, Cockateel);    // OK, assuming Cockateel derives from Bird
>> inst Cage(Bird, Bird);         // OK
>> inst Cage(Bird, Collie);       // Error - Collie does not derive from Bird
>> inst Cage(Bird, Animal);       // Error - inheritance order is backwards
[clip]
>> template Calculator(T like NUMERIC) {/*whatever*/}
[clip]
>It occurs to me that this does fit in with the D template syntax:
>
>    template Calculator(T : NUMERIC) { ... }
>
>means that T can be either NUMERIC or a class derived from NUMERIC (if NUMERIC is a class or interface). Your case 3 would be:
>
>    template Cage(B, D : B) {/*whatever*/}
>
>which would constrain D to be the same as B or derived from B.

Even better.  The 'T : NUMERIC' syntax is much like the Eiffel syntax I was coming from.  I didn't know if it would work that way in D or not.  The examples with : were demonstrating partial template specialization (or the D equivalent) and the ability to pull types out of pointers to / arrays of types.  I didn't know if the constraint system supported general purpose "is a" constraints, including direct and indirect inheritance.

There appears to be some semantic difference:

template Calc(T : NUMERIC)
template Other(T : T[])

In the first case, I would instantiate Calc with a class that was derived from NUMERIC (or NUMERIC itself, if NUMERIC is concrete).  But in the second case, I instantiate Calc with an array, and the compiler extracts the type.  If these two cases behaved identically, then either:

1. Take the first example as the standard -- Other must now be instantiated with a single variable, and the type of that variable is required to support the interface of an array of that type.  T is required to act as if it is an array of T, which it can't do.

2. Take the second example as the standard -- Calc must now be instantiated with a NUMERIC, and the D compiler will deduce an appropriate type for T.  I suppose this would be possible with RTTI, or by allowing the compiler to take derivatives of NUMERIC directly...

I guess my mental hangup is that 'T:NUMERIC' means "T must support the NUMERIC interface" (derive from it, whatever), but 'T:T[]' means "given a T[], extract T".  Having had Eiffel training in constrained genericity, I tend to favor the "must support" semantics, but I am trying to maintain an open mind...

I know that you've been thinking about this for quite some time, and I also know that it is difficult to come up with small simple examples that illustrate the intended usage of some of these features.  (My examples when trying to show this stuff to my coworkers is almost always horrible)  The 'template X(T,T:T[])' examples so far seem like they shouldn't need the second parameter, since if you know T you can always make a T[] inside the template.  In C++ you need this sort of thing in case the user is using smart array classes, smart pointer classes, iterators, etc.  But in D, arrays are arrays, pointers are pointers, etc, so there doesn't seem to be the need to allow the user to specify *how* to make an array out of the base type.  Could you give us an example (even if it is somewhat complicated) of the case you were considering when you made the 'template X(T,T:T[])' behavior?  I'm sure there's a reason that I'm just overlooking.

Thanks,
Mac


August 21, 2002
"Patrick Down" <pat@codemoon.com> wrote in message news:Xns9271999977E06patcodemooncom@63.105.9.61...
> Does the statement "Semantic analysis is not done until instantiated." mean that the tempate will pick up variables and functions in the scope in which it is instantiated?

Nope. The only thing it will pick up from the instantiation scope is the template argument types.

> // File: temp.d
> template Foo(T)
> {
>   bit Bar(T a)
>   {
>     return a < BorgConst;
>   }
> }
>
> // File alpha.d
> import temp;
>
> int BorgConst = 12;
>
> in Foo(int) here;
>
> here.Bar(5); // returns true
>
> If this is true it would seem to perhaps be at odds with
> this statement "Multiple instantiations of a TemplateDeclaration
> with the same TemplateParameterList all will refer to the same
> instantiation."

Correct, which is one reason why it is false (and your example will fail to compile with a "BorgConst undefined" error). Templates are instantiated in the scope in which the template is declared. This avoids the whole C++ mess of "non-dependent names" versus "dependent names" and their subtly different lookup schemes.

Clean separation between syntax and semantics is what makes this easy to do in D, and nearly impossible in C++.


August 21, 2002
"Martin M. Pedersen" <mmp@www.moeller-pedersen.dk> wrote in message news:ak0sto$ic1$1@digitaldaemon.com...
> "Walter" <walter@digitalmars.com> wrote in message news:ak0j61$1r42$2@digitaldaemon.com...
> > I think I'd rather use the keyword 'instance' <g>.
>
> Couldn't it cause some confusion with instances of classes, which are objects? Instances of a template is an interely different thing. How about "concrete", meaning that you make the abstract template concrete by supplying types.

It could, but instantiations of templates, as well as instantiations of classes, are both commonly referred to as instances. Your point is likely why Ada instantiates templates with the 'new' keyword.


August 21, 2002
Hi,

"Walter" <walter@digitalmars.com> wrote in message news:ajvgsb$6gt$1@digitaldaemon.com...
> www.digitalmars.com/template.html
>
> Notice how short it is <g>. Ok, what did I miss?

I would like the ability to pass constants such as literals and function pointers. For example, a smart-pointer could have a special free function given as argument.

A feature I have been missing in C++, is the ability to have conditional compilation based on the concrete types. This would be useful if eg. 95% of the template code is the same, but the rest needs to be different. In some cases, it would also allow the template to provide a more efficient implementation for a specific type.

Regards,
Martin M. Pedersen



August 21, 2002
"Walter" <walter@digitalmars.com> wrote in news:ak0t51$k2o$1@digitaldaemon.com:

> 
> "Pavel Minayev" <evilone@omen.ru> wrote in message news:CFN374899452836458@news.digitalmars.com...
>>Container(int).Stack s;
>>This is to avoid cluttering the namespace with continuous lists of
>>instantiations (which is going to happen with any large program
>>using templates extensively).
> 
> I forgot to mention that has syntax parsing problems, too. How about this:
> 
> instance Container(int).Stack s;
> 
> ?
> 
> 

Just to throw it out:
    	Stack s from instance of Container(int);
or:
    	Stack s from instance Container(int);
or:
    	Stack s instance Container(int);
or:
    	Stack s in Container(int);
August 21, 2002
On Wed, 21 Aug 2002 13:10:47 -0700 "Walter" <walter@digitalmars.com> wrote:

> I forgot to mention that has syntax parsing problems, too. How about this:
> 
> instance Container(int).Stack s;
> 
> ?

This is also fine!
August 21, 2002
Hi,

"Martin M. Pedersen" <mmp@www.moeller-pedersen.dk> wrote in message news:ak0udv$sch$1@digitaldaemon.com...
> For example, a smart-pointer could have a special free function > given as
argument.

It reminds me: Smart pointers would need the ability to redefine the member operator. Is it feasible in D?

Regards,
Martin M. Pedersen



August 21, 2002
"Martin M. Pedersen" <mmp@www.moeller-pedersen.dk> wrote in message news:ak0udv$sch$1@digitaldaemon.com...
> I would like the ability to pass constants such as literals and function pointers. For example, a smart-pointer could have a special free function given as argument.

I've thought about this. Wouldn't it make sense to have an argument that is an interface, the implementation of which has the desired special free function?

    interface Free { void special_free(void *); }
    template Foo(T, U : Free)
    {
        ...
        U.special_free(p);
        ...
    }

    class Bar : Free
    {
        void special_free(void *p) { ... }
    }
    instance Foo(int, Bar) abc;


> A feature I have been missing in C++, is the ability to have conditional compilation based on the concrete types. This would be useful if eg. 95%
of
> the template code is the same, but the rest needs to be different. In some cases, it would also allow the template to provide a more efficient implementation for a specific type.

This would be a valuable feature, but there are many different ways to do it. I haven't gone far down the path of exploring them.


August 21, 2002
"Mac Reiter" <Mac_member@pathlink.com> wrote in message news:ak0tm6$njk$1@digitaldaemon.com...
> There appears to be some semantic difference:
>
> template Calc(T : NUMERIC)
> template Other(T : T[])
>
> In the first case, I would instantiate Calc with a class that was derived
from
> NUMERIC (or NUMERIC itself, if NUMERIC is concrete).  But in the second
case, I
> instantiate Calc with an array, and the compiler extracts the type.  If
these
> two cases behaved identically, then either:
>
> 1. Take the first example as the standard -- Other must now be
instantiated with
> a single variable, and the type of that variable is required to support
the
> interface of an array of that type.  T is required to act as if it is an
array
> of T, which it can't do.
>
> 2. Take the second example as the standard -- Calc must now be
instantiated with
> a NUMERIC, and the D compiler will deduce an appropriate type for T.  I
suppose
> this would be possible with RTTI, or by allowing the compiler to take derivatives of NUMERIC directly...
>
> I guess my mental hangup is that 'T:NUMERIC' means "T must support the
NUMERIC
> interface" (derive from it, whatever), but 'T:T[]' means "given a T[],
extract
> T".  Having had Eiffel training in constrained genericity, I tend to favor
the
> "must support" semantics, but I am trying to maintain an open mind...

You're right, there is a subtle difference there. I think if the rule were if T is in the specialization, then the value of T is extracted. If T is not in the specialization, T is whatever the whole specialization type is (or derived from it).

> I know that you've been thinking about this for quite some time, and I
also know
> that it is difficult to come up with small simple examples that illustrate
the
> intended usage of some of these features.  (My examples when trying to
show this
> stuff to my coworkers is almost always horrible)  The 'template
X(T,T:T[])'
> examples so far seem like they shouldn't need the second parameter, since
if you
> know T you can always make a T[] inside the template.  In C++ you need
this sort
> of thing in case the user is using smart array classes, smart pointer
classes,
> iterators, etc.  But in D, arrays are arrays, pointers are pointers, etc,
so
> there doesn't seem to be the need to allow the user to specify *how* to
make an
> array out of the base type.  Could you give us an example (even if it is somewhat complicated) of the case you were considering when you made the 'template X(T,T:T[])' behavior?  I'm sure there's a reason that I'm just overlooking.

I don't have a good example. One thing about C++, there seems to be a veritable army of very smart people discovering clever things to do with C++ templates that weren't anticipated in the initial design of templates. The X(T,T:T[]) falls out of the specialization syntax, so there's no obvious reason to disallow it.


August 21, 2002
Hi,

"Walter" <walter@digitalmars.com> wrote in message news:ak119a$1ga1$1@digitaldaemon.com...
> I've thought about this. Wouldn't it make sense to have an argument that
is
> an interface, the implementation of which has the desired special free function?

That would do it, I think :-)

> > A feature I have been missing in C++, is the ability to have conditional compilation based on the concrete types.
> This would be a valuable feature, but there are many different ways to do it. I haven't gone far down the path of exploring them.

My solution to the missing feature in C++, has sometimes been to use overloaded functions outside the template, but I have also resorted to not using a template at all, but auto-generate classes instead by some special preprocessing.

Regards,
Martin M. Pedersen