www.digitalmars.com         C & C++   DMDScript  

D - more templates (and a bit covariance)

reply "Carlos Santander B." <carlos8294 msn.com> writes:
I tried to solve that foreach()+postinc() problem, so I created an
interface. Anyway, my code now looks like this:

module foreach;
interface INextable { INextable next(); }     //<-------- 1
template ForEach(InputIter) {
    alias void delegate (InputIter) F;
    F foreach(InputIter first,InputIter last,F f) {
        while (first!=last) {
            f(first);
            if ( cast(INextable)first )
                first=cast(InputIter) first.next();     //<-------- 2
            else
                first++;     //<-------- 3
        }
        return f;
    }
}

The thing is that in [2], when I instance ForEach with ints or any other, I
get "no property next() for int". And in [3], when I instance with Node or
something else, I get "first is a Node, not a scalar". Obviously, that's
expected, in a way... It'd desirable if the compiler could strip code from
templates according to the instanciation (is that a word?).

The solution was to have a specialized template for INextable, so I could
properly separate one implementation from the other. But, then again,
there's duplicated code. Here's where template inheritance would be good. It
has been asked before, now I'm asking for it again.

Now, line 1 has nothing to do with templates.

interface INextable { INextable next(); }     //<-------- 1

If, I do this:

class Node : INextable { Node next() { ... } }

I get "Node doesn't implement INextable.next()". Didn't D have covariance
(or contravariance or whatever the name is)? I know I can implement it to
return INextable, but it requires lots of casting in other parts of the
code. Again, I could be with the wrong idea. If I'm right, good for me. If
I'm wrong, then could somebody care to explain?

-------------------------
Carlos Santander
I tried to solve that foreach()+postinc() problem, so I created an
interface. Anyway, my code now looks like this:

module foreach;
interface INextable { INextable next(); }     //<-------- 1
template ForEach(InputIter) {
    alias void delegate (InputIter) F;
    F foreach(InputIter first,InputIter last,F f) {
        while (first!=last) {
            f(first);
            if ( cast(INextable)first )
                first=cast(InputIter) first.next();     //<-------- 2
            else
                first++;     //<-------- 3
        }
        return f;
    }
}

The thing is that in [2], when I instance ForEach with ints or any other, I
get "no property next() for int". And in [3], when I instance with Node or
something else, I get "first is a Node, not a scalar". Obviously, that's
expected, in a way... It'd desirable if the compiler could strip code from
templates according to the instanciation (is that a word?).

The solution was to have a specialized template for INextable, so I could
properly separate one implementation from the other. But, then again,
there's duplicated code. Here's where template inheritance would be good. It
has been asked before, now I'm asking for it again.

Now, line 1 has nothing to do with templates.

interface INextable { INextable next(); }     //<-------- 1

If, I do this:

class Node : INextable { Node next() { ... } }

I get "Node doesn't implement INextable.next()". Didn't D have covariance
(or contravariance or whatever the name is)? I know I can implement it to
return INextable, but it requires lots of casting in other parts of the
code. Again, I could be with the wrong idea. If I'm right, good for me. If
I'm wrong, then could somebody care to explain?

-------------------------
Carlos Santander
Aug 09 2003
parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh41eh$6e6$1 digitaldaemon.com...
 -------------------------
 Carlos Santander
 I tried to solve that foreach()+postinc() problem, so I created an
 interface. Anyway, my code now looks like this:

 module foreach;
 interface INextable { INextable next(); }     //<-------- 1
 template ForEach(InputIter) {
     alias void delegate (InputIter) F;
     F foreach(InputIter first,InputIter last,F f) {
         while (first!=last) {
             f(first);
             if ( cast(INextable)first )
                 first=cast(InputIter) first.next();     //<-------- 2
             else
                 first++;     //<-------- 3
         }
         return f;
     }
 }

 The thing is that in [2], when I instance ForEach with ints or any other,
I
 get "no property next() for int". And in [3], when I instance with Node or
 something else, I get "first is a Node, not a scalar". Obviously, that's
 expected, in a way... It'd desirable if the compiler could strip code from
 templates according to the instanciation (is that a word?).

 The solution was to have a specialized template for INextable, so I could
 properly separate one implementation from the other. But, then again,
 there's duplicated code. Here's where template inheritance would be good.
It
 has been asked before, now I'm asking for it again.
Template inheritance would solve a few issues but it might create more (I've wished for it in some cases) templates as types would also be good. have you considered two levels to your template ? as in template foreach_next_getter( T : INextable ) { T get_next( T item ) { return item.next(); } } template foreach_next_getter( T : int ) { T get_next( T item ) { return item+1; } } template ForEach(InputIter) { alias void delegate (InputIter) F; alias instance foreach_next_getter( InputIter ) next_getter; F foreach(InputIter first,InputIter last,F f) { while (first!=last) { f(first); first = next_getter.get_next( first ); } return f; } }
 Now, line 1 has nothing to do with templates.

 interface INextable { INextable next(); }     //<-------- 1

 If, I do this:

 class Node : INextable { Node next() { ... } }

 I get "Node doesn't implement INextable.next()". Didn't D have covariance
 (or contravariance or whatever the name is)? I know I can implement it to
 return INextable, but it requires lots of casting in other parts of the
 code. Again, I could be with the wrong idea. If I'm right, good for me. If
 I'm wrong, then could somebody care to explain?
I belive its 'cos D has contra_bla_bla_bla on object methods but COM (Interfaces) do not with a two level template you can do template foreach_next_getter( T : Node ) { T get_next( T item ) { return cast(T)item.next(); } } or make Nextable a base class not an interface (again not a perfect solution).
Aug 09 2003
parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:bh43p1$8pn$1 digitaldaemon.com...
|
| Template inheritance would solve a few issues but it might create more
(I've
| wished for it in some cases)
| templates as types would also be good.
|
| have you considered two levels to your template ? as in
|
| template foreach_next_getter( T : INextable ) {
|     T get_next( T item ) { return item.next(); }
| }
|
| template foreach_next_getter( T : int ) {
|     T get_next( T item ) { return item+1; }
| }
|
| template ForEach(InputIter) {
|     alias void delegate (InputIter) F;
|     alias instance foreach_next_getter( InputIter ) next_getter;
|     F foreach(InputIter first,InputIter last,F f) {
|         while (first!=last) {
|             f(first);
|             first = next_getter.get_next( first );
|         }
|         return f;
|     }
| }
|

Well, that's another solution. But again there's duplicated code. Now it's
easy because we're only talking about 2 kinds of foreach_next_getter, with
only 1 method on each one. But suppose there are tens of different kinds of
foreach_next_getter, or that it could have not one but many methods. Then it
becomes hard to mantain.

|
| I belive its 'cos D has contra_bla_bla_bla on object methods but COM
| (Interfaces) do not
| with a two level template you can do
| template foreach_next_getter( T : Node ) {
|     T get_next( T item ) { return cast(T)item.next(); }
| }

That's adding more complexity to the above said.

|
| or make Nextable a base class not an interface (again not a perfect
| solution).
|
|

I'd rather not, since D doesn't support multiple inheritance.

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 2003-08-04
Aug 09 2003
next sibling parent reply "Matthew Wilson" <dmd synesis.com.au> writes:
 I'd rather not, since D doesn't support multiple inheritance.
Eeek! That's another hurdle our template libraries will have to leap. I forgot all about that. Maybe we should allow MI in the case of templates, where they follow the rules of veneers (http://synesis.com.au/resources/articles/cpp/veneers.pdf)?
Aug 09 2003
parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Matthew Wilson" <dmd synesis.com.au> wrote in message
news:bh47o6$cbq$1 digitaldaemon.com...
 I'd rather not, since D doesn't support multiple inheritance.
Eeek! That's another hurdle our template libraries will have to leap. I forgot all about that. Maybe we should allow MI in the case of templates, where they follow the rules of veneers (http://synesis.com.au/resources/articles/cpp/veneers.pdf)?
unfortunatly all D member functions are virtual and I can't see any references to 'final' I'd like to see veneer classes as part of the lang allowing primative values or structures to have member functions and will not require any operator new (as such) veneer class myint : int { int add( int i ) { return this + i; } // is infact myint::add( int this, int i ); } int func( int i ) { myint ii(i); // realy just an alias to i. return ii.add( 3 ); // class myint::add( i, 3 ); } veneer classes can 'extend' any item even a veneer. but no member function can overload any perviously defined member function (not mentioned in your doc?) and can not implement any interfaces. casting : as the veneer is not "real" then casting a base class to a veneer is just a way to tell the compiler what you want to do. int i; int b = (cast(myint)i).add( 44 ); this could include automatic promotion (int is passable as myint) int func( myint ii ) { return ii.add( 55 ); } int i = 9; int b = func( i );
Aug 09 2003
parent "Matthew Wilson" <matthew stlsoft.org> writes:
As I'm sure you appreciate, the veneer concept was originally aimed at C++,
specifically to legitimise:

 - the inheritance from types that do not have a virtual destructor
 - the use of arrays of derived types being passed by pointers to
base-class-pointer manipulation functions.

Both of these are danger areas in general, hence the stringent restrictions
on what a "veneer" actually is.

I've no doubt that we could adapt the concept for D, although since neither
of its two raisons d'etre exist in D, perhaps it would be better to define a
new concept (with a new name).

The reason I mentioned it in the thread is that MI is avoided in D (& Java &
.NET) because of the multiple vtables and the extended object size, and all
that other horrid stuff in C++ associated with two non-empty classes coming
together; I'm sure we all know and despise the virtual base initialiser!

If a type does not add vtable, or size, to a type then I can't see a good
reason for denying it, excepting the difficulty in compiler implementation.
I think this lack will be an important problem when we come to doing fancy
template stuff, although I do account for the fact that I'm stuck in a C++
way of thinking, and could therefore be entirely wrong. ;)


"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:bh4b28$f70$1 digitaldaemon.com...
 "Matthew Wilson" <dmd synesis.com.au> wrote in message
 news:bh47o6$cbq$1 digitaldaemon.com...
 I'd rather not, since D doesn't support multiple inheritance.
Eeek! That's another hurdle our template libraries will have to leap. I forgot all about that. Maybe we should allow MI in the case of
templates,
 where they follow the rules of veneers
 (http://synesis.com.au/resources/articles/cpp/veneers.pdf)?
unfortunatly all D member functions are virtual and I can't see any references to 'final' I'd like to see veneer classes as part of the lang allowing primative
values
 or structures to have member functions and will not require any operator
new
 (as such)

 veneer class myint : int {
     int add( int i ) { return this + i; } // is infact myint::add( int
this,
 int i );
 }

 int func( int i )
 {
     myint ii(i);   // realy just an alias to i.
     return ii.add( 3 ); // class myint::add( i, 3 );
 }

 veneer classes can 'extend' any item even a veneer. but no member function
 can overload any perviously defined member function (not mentioned in your
 doc?) and can not implement any interfaces.
 casting :
     as the veneer is not "real" then casting a base class to a veneer is
 just a way to tell the compiler what you want to do.
     int i;
     int b = (cast(myint)i).add( 44 );
 this could include automatic promotion (int is passable as myint)
 int func( myint ii ) { return ii.add( 55 ); }
 int i = 9;
 int b = func( i );
Aug 09 2003
prev sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh47il$c3v$1 digitaldaemon.com...
 "Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
 news:bh43p1$8pn$1 digitaldaemon.com...
 |
 | Template inheritance would solve a few issues but it might create more
 (I've
 | wished for it in some cases)
 | templates as types would also be good.
 |
 | have you considered two levels to your template ? as in
 |
 | template foreach_next_getter( T : INextable ) {
 |     T get_next( T item ) { return item.next(); }
 | }
 |
 | template foreach_next_getter( T : int ) {
 |     T get_next( T item ) { return item+1; }
 | }
 |
 | template ForEach(InputIter) {
 |     alias void delegate (InputIter) F;
 |     alias instance foreach_next_getter( InputIter ) next_getter;
 |     F foreach(InputIter first,InputIter last,F f) {
 |         while (first!=last) {
 |             f(first);
 |             first = next_getter.get_next( first );
 |         }
 |         return f;
 |     }
 | }
 |

 Well, that's another solution. But again there's duplicated code. Now it's
 easy because we're only talking about 2 kinds of foreach_next_getter, with
 only 1 method on each one. But suppose there are tens of different kinds
of
 foreach_next_getter, or that it could have not one but many methods. Then
it
 becomes hard to mantain.
I've very lost! where have I duplicated code ?? in you example you had an `if else` (2 independant sets of code) in mine 2 templates instead. I can't see any duplicated code. o.k. I should have written template foreach_next_getter( T : int | char | byte |uint|long|ulong|short|ushort|ClassWithOpPlusInt ) { T get_next( T item ) { return item+1; } } template foreach_next_getter( T : INextable | MYbaseClassThatHasNext ) { T get_next( T item ) { return item.next(); } } if you have more methods prev etc then add another layer for them you only need to write a new template if one of the others does not do what you require. template foreach_prev_getter( T : int | char | byte |uint|long|ulong|short|ushort) { T get_prev( T item ) { return item-1; } } template foreach_next_and_prev_getter( T ) { alias instance foreach_next_getter( T ) feng; alias instance foreach_prev_getter( T ) fepg; alias get_next feng.get_next; alias get_prev fepg.get_next; } a few aliases but no duplicated code. NOTE: you only need ONE foreach_next_and_prev_getter the one above.
 |
 | I belive its 'cos D has contra_bla_bla_bla on object methods but COM
 | (Interfaces) do not
 | with a two level template you can do
 | template foreach_next_getter( T : Node ) {
 |     T get_next( T item ) { return cast(T)item.next(); }
 | }

 That's adding more complexity to the above said.
I can see your not going to be satisifed until the D compiler writes your program for you!
 |
 | or make Nextable a base class not an interface (again not a perfect
 | solution).
 |
 |

 I'd rather not, since D doesn't support multiple inheritance.
its not a good solution by any means but if you object to writing a 4 line template for each class it does allow you to just add your class name to the classes that match with the template that uses { return item.next(); }
Aug 09 2003
parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
| "Carlos Santander B." <carlos8294 msn.com> wrote in message
| news:bh47il$c3v$1 digitaldaemon.com...
| > becomes hard to mantain.
                            ^^^^^^^^^^
"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:bh48t5$dcv$1 digitaldaemon.com...
|
|
| I've very lost! where have I duplicated code ??
| in you example you had an `if else` (2 independant sets of code) in mine 2
| templates instead.
| I can't see any duplicated code.
|
| ...
|
| a few aliases but no duplicated code.
| NOTE: you only need ONE foreach_next_and_prev_getter the one above.
|
| ...
|
| I can see your not going to be satisifed until the D compiler writes your
| program for you!
|

Ok, maybe I shouldn't have said duplicated code. I meant hard to maintain. I
can see there's no duplicated code, but eventually all those templates could
become too many or too complex or both.

And no, I don't want the compiler to write my program: I just want it to
help me to write it. And, before somebody else says it, I don't think that's
laziness because if we didn't want any help we could all go back to
assembler, but instead we're all giving suggestions, ideas, etc. that could
make D give us more help, aren't we?

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 2003-08-04
Aug 10 2003
parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh5ha3$1h3v$1 digitaldaemon.com...
 "Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
 news:bh48t5$dcv$1 digitaldaemon.com...
 | I've very lost! where have I duplicated code ??
 | in you example you had an `if else` (2 independant sets of code) in mine
2
 | templates instead.
 | I can't see any duplicated code.
 | a few aliases but no duplicated code.
 | NOTE: you only need ONE foreach_next_and_prev_getter the one above.
 |
 | I can see your not going to be satisifed until the D compiler writes
your
 | program for you!
 |

 Ok, maybe I shouldn't have said duplicated code. I meant hard to maintain.
I
 can see there's no duplicated code, but eventually all those templates
could
 become too many or too complex or both.
how exactly ? (see the end of posting)
 And no, I don't want the compiler to write my program: I just want it to
 help me to write it. And, before somebody else says it, I don't think
that's
 laziness because if we didn't want any help we could all go back to
 assembler, but instead we're all giving suggestions, ideas, etc. that
could
 make D give us more help, aren't we?
what you are saying is you want a bit more syntactix sugar to help you, what every language you write in there is always a bit more syntactic sugar that will help someone out (inner classes in Java are just one example, as are anon classes or inner functions (inner functions in C can be done by creating a struct for you locals (and params etc if you know the layout the compiler uses)) to steal an example from another post ... does this make sence to you ? int main () { vector<int> v; copy(istream_iterator<int>(cin), istream_iterator<int>(), back_inserter()); sort(v.begin(), v.end(), greater<int>()); copy(v.begin(), v.end(), ostream_iterator<int>(Cout, " ")); return 0; // to make MSVC happy } if so, go have a look and the definition of istream_iterator .. you will see much of it is very similar to the example I gave template<class T, class T_Traits = SomeTraits<T> > class Something { typedef T BaseType; typedef T_Traits WorkingType; ... } what exactly do you want ? to me one template (for_each) which is generic for all types and one template for_each_traits which either imports or has the required next/prev functions maintanance is easy ... you look for the template that matches your type, no matter the params of for_each there will be one foreach_next_getter for your type. your example was hard to maintain (and slow with an if inside a loop) my version was a function call potentially inlineable. for every new type you would have to add further condition in your loop (somehow) mine just means you add a new foreach_next_getter for your new type (which does not have .next() or operator + int) if you don't understand something it looks complex even when it is not. the stl is a great example: easy to use (once you've got to grips with what it can do) but I'd not want to have to maintain it, its not the worse spagetti code I've seen and its not helped much by C++'s syntax and verbose names but if you take the time to look; it is quite simple in design but takes advantage of the lang it written in to make its usage easy please explain what feature D templates lack that would make your example any easier to use than the version I sent you ? and what you see as the main maintanance stumbling blocks (to me adding a "traits" template/class for each user defined type that does not fit into the already written types (numeric or INextable or a class that implements `this.class next()` ) is acceptable)
Aug 10 2003
next sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:bh5lqj$1l48$1 digitaldaemon.com...
| what you are saying is you want a bit more syntactix sugar to help you,
what
| every language you write in there is always a bit more syntactic sugar
that
| will help someone out (inner classes in Java are just one example, as are
| anon classes or inner functions (inner functions in C can be done by
| creating a struct for you locals (and params etc if you know the layout
the
| compiler uses))
|
| to steal an example from another post ...
| does this make sence to you ?
| int main ()
| {
| vector<int> v;
| copy(istream_iterator<int>(cin), istream_iterator<int>(),
back_inserter());
| sort(v.begin(), v.end(), greater<int>());
| copy(v.begin(), v.end(), ostream_iterator<int>(Cout, " "));
| return 0;  // to make MSVC happy
| }
|
| if so, go have a look and the definition of istream_iterator ..
| you will see much of it is very similar to the example I gave
|
| template<class T, class T_Traits = SomeTraits<T> > class Something {
|     typedef T BaseType; typedef T_Traits WorkingType;
| ...
| }
|

That doesn't help me that much. Like I said a couple of weeks ago, I
recently had my first experience with C++ STL (and it was only for string)
so I don't know how it works, what exactly it does, etc. Yes, my code was
based on the STL for_each, but it was because I wanted to have an idea of
what it did. No, I didn't know what it did. I thought it let you do this:

for_each( something , container ) { ... do something ... }

So I wanted to know how it was yielding values. (I think I got a bit OT)

| what exactly do you want ?
| to me one template (for_each) which is generic for all types
| and one template for_each_traits which either imports or has the required
| next/prev functions
| maintanance is easy ... you look for the template that matches your type,
no
| matter the params of for_each there will be one foreach_next_getter for
your
| type.

Once again: I'm not familiar with those kind of things. To be honest, I
haven't actually done templates in C++ besides the trivial max(), min(),
swap(), and such.

| your example was hard to maintain (and slow with an if inside a loop) my
| version was a function call potentially inlineable. for every new type you
| would have to add further condition in your loop (somehow)
| mine just means you add a new foreach_next_getter for your new type (which
| does not have .next() or operator + int)

That shows you have more experience and more knowledge in the subject than
me.

| if you don't understand something it looks complex even when it is not.
the
| stl is a great example: easy to use (once you've got to grips with what it
| can do) but I'd not want to have to maintain it, its not the worse
spagetti
| code I've seen and its not helped much by C++'s syntax and verbose names
but
| if you take the time to look; it is quite simple in design but takes
| advantage of the lang it written in to make its usage easy
|
| please explain what feature D templates lack that would make your example
| any easier to use than the version I sent you ? and what you see as the
main
| maintanance stumbling blocks (to me adding a "traits" template/class for
| each user defined type that does not fit into the already written types
| (numeric or INextable or a class that implements `this.class next()` ) is
| acceptable)
|

After all you've said I must say it's a good solution, ok. What I wanted (in
the beginning) was that the compiler could compile code based on the type. I
had:

class A {}
template T (U) {
    void foo(U x) {
        if ( cast(A) x) bar();
        else baz();
    }
}

So, what I wanted was: if T is A, compile *only* the if part. If it's not,
compile *only* the else part. That's what I wanted. I thought it could be
done. I thought it was a good option. But I'm willing to accept other
options, like yours.

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 2003-08-04
Aug 10 2003
next sibling parent reply "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh5mvr$1m89$1 digitaldaemon.com...
 class A {}
 template T (U) {
     void foo(U x) {
         if ( cast(A) x) bar();
         else baz();
     }
 }

 So, what I wanted was: if T is A, compile *only* the if part. If it's not,
 compile *only* the else part. That's what I wanted. I thought it could be
 done. I thought it was a good option. But I'm willing to accept other
 options, like yours.
think of it this way why have a runtime check for the type of A when the compiler can do it for you via template matching ... so the D way to do this (as far as I know) is .... template T(U : A) { // matchs A or sub class void foo( U x ) { bar(); } } template T( U ) { // matches everything void foo( U x ) { baz(); } } or template T_Traits( U : A ) { void do_foo( U x ) { bar(); } template T_Traits( U ) { void do_foo( U x ) { baz(); } template T (U ) { alias instance T_Traits( U ) worker; void foo( U x ) { worker.do_foo( x ); } } unfortunatly you can't do template T( U, W = T_Traits( U ) ) { void foo( U x ) { w.do_foo( x ); } as you would in C++ which also means you can't do template T( U, W ) { void foo( U x ) { W.do_foo(x); } } template T( U ) { alias foo instance T( U, instance T_Traints( U )).foo; } you could use a class template T_Worker( U ) { class worker { static void do_foo( U x ) { bar(); } } } template T( U ) { alias foo instance T( U, instance T_Worker( U ).worker ).foo; // so W.do_foo is void T_Worker<U>::worker::do_foo( U x ) ... } to look and the iterator.d posted in another thread template Algorithm(Iterator, ItemType) { alias void delegate (ItemType) Delegate; void forEach(Iterator it, Delegate f) { while (it.hasNext()) f(it.next()); } alias void function (ItemType) Function; void forEach(Iterator it, Function f){ while (it.hasNext()) f(it.next()); } } it would be good to be able to merge the two forms without having to add a 3rd template param such as template Algorithm_worker(Iterator, FPtrType ) { void forEach(Iterator it, FPtrType f) { while (it.hasNext()) f(it.next()); } } template Algorithm(Iterator, ItemType) { alias void delegate (ItemType) Delegate; alias void forEach(Iterator it, Delegate f) instance Algorithm_worker(Iterator, Delegate).forEach; alias void function (ItemType) Function; alias void forEach(Iterator it, Function f) instance Algorithm_worker(Iterator, Function).forEach; } this would also be useful for veneer classes (if they are every supported) instead of writing template Algorithm(Iterator, ItemType) { alias void delegate (ItemType) Delegate; void forEach(Iterator it, Delegate f) { instance Algorithm_worker(Iterator, Delegate).forEach( it, f ); } alias void function (ItemType) Function; void forEach(Iterator it, Function f) { instance Algorithm_worker(Iterator, Function).forEach( it, f); } } and would be even nicer to have MI in templates template Algorithm(Iterator, ItemType) : Algorithm_worker(Iterator, void delegate (ItemType)), Algorithm_worker(Iterator, void function (ItemType)) { }
Aug 10 2003
parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
"Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
news:bh5oss$1o45$1 digitaldaemon.com...
|
| think of it this way why have a runtime check for the type of A when the
| compiler can do it for you via template matching ...

I wanted it to be done at compile time. I thought it could be done.

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 2003-08-04
Aug 10 2003
parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh6aia$28n2$1 digitaldaemon.com...
 "Mike Wynn" <mike.wynn l8night.co.uk> wrote in message
 news:bh5oss$1o45$1 digitaldaemon.com...
 |
 | think of it this way why have a runtime check for the type of A when the
 | compiler can do it for you via template matching ...

 I wanted it to be done at compile time. I thought it could be done.
it can ... template matching template whatever( T : Object ) { .. } template whatever( T : int | short ) { .. } template whatever( T : uint | ushort ) { .. } template whatever( T : T[] ) { .. } (int[] =>T<-int) template whatever( T : T* ) { .. } ( int* =>T<-int) template whatever( T : T[U] ) { .. }(int[char[]] => T<-int, U<-char[] ) // should be not checked this one etc. but template( T ) { void func( T A ) { if ( cast(int)A ) { } } } will be runtime I had considerer proposing template( T ) { if ( T instanceof A ) { void func( int a ) { ... } } else { void func() { ... } } } for a way of compile time decisions on what the template does but that is just the same as the above, (and a switch on type) only difference is where the code is, and how complex the compiler has to be, the former (the current) way is a lot easier on the compiler/parser and can do all the same things (and more).
Aug 10 2003
prev sibling parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
Other languages such as OCaml have this nifty "match" construct that does
just this sort of thing without the if's and casts.  Probably could be
integrated into the switch statement somehow.  If the type is known at
compile time it could certainly replace the functionality of template
specialization.  But this is generally only one of the ways to approach
solving the problem.  If you look at the problem in another way, different
solutions emerge.  Such as traits classes, template specialization.

Sean

"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh5mvr$1m89$1 digitaldaemon.com...
 After all you've said I must say it's a good solution, ok. What I wanted
(in
 the beginning) was that the compiler could compile code based on the type.
I
 had:

 class A {}
 template T (U) {
     void foo(U x) {
         if ( cast(A) x) bar();
         else baz();
     }
 }

 So, what I wanted was: if T is A, compile *only* the if part. If it's not,
 compile *only* the else part. That's what I wanted. I thought it could be
 done. I thought it was a good option. But I'm willing to accept other
 options, like yours.
Aug 11 2003
parent Ilya Minkov <midiclub 8ung.at> writes:
Sean L. Palmer wrote:
 Other languages such as OCaml have this nifty "match" construct that does
 just this sort of thing without the if's and casts.  Probably could be
 integrated into the switch statement somehow.
That reminds me of Sather's typecase statement, which is syntanctially similar to a case statement, which is its equivalent of switch. Semantically, it is different and works more like a match construct - it tries to safely cast an expression into the types in the given order, and executes the branch which matches first. This also means that one should list the types from specific to general, else the more specific ones cannot be handled. Is there any current way to make such typematching in D? If not, i would vote for a match-like switch extension. It shall not be fallthrough, and may become a general switch replacement for some programmers who have been opposed to fall-through switch. I believe i have already put up a link somewhere, describing how match-like construct can be implemented on top of C++ -- which is enough information to implement it in D. If someone is interested, i can dig it up again. -i.
Aug 11 2003
prev sibling parent reply "Carlos Santander B." <carlos8294 msn.com> writes:
(When template inheritance could be useful)
Take a look at Farmer's implementation (in the postinc thread). He has 2
templates MyFuncs (lines 108 and 125), and in each he has a class Stateful,
both identical. I don't want to be annoying with this, but I think you
understand that if that was the case for more and more templates, classes,
functions, etc., it wouldn't be a simple task to keep the consistency across
all of them. That's what I was trying to say. (Now, if I'm again using the
wrong words, please excuse me.)

—————————————————————————
Carlos Santander


---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.507 / Virus Database: 304 - Release Date: 2003-08-04
Aug 10 2003
next sibling parent "Mike Wynn" <mike.wynn l8night.co.uk> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in message
news:bh5nmm$1mt8$1 digitaldaemon.com...
 (When template inheritance could be useful)
 Take a look at Farmer's implementation (in the postinc thread). He has 2
 templates MyFuncs (lines 108 and 125), and in each he has a class
Stateful,
 both identical. I don't want to be annoying with this, but I think you
 understand that if that was the case for more and more templates, classes,
 functions, etc., it wouldn't be a simple task to keep the consistency
across
 all of them. That's what I was trying to say. (Now, if I'm again using the
 wrong words, please excuse me.)

 -------------------------
 Carlos Santander
I agree at times a design can be better with a bit of duplication, you seemed to be arguing that it was bad and wanted to remove the duplication, which you can with another template etc like object heirachies you have a chose to cut'n'paste several copies of the same code or template it (with special cases if need be) maintainance on either can be just as bad; with several classes containing the same code you have to fix bugs in all (if there is a bug in one chances are it will be in all, and you might miss one of the places you used that code) with the multi template system, it can be hard to find where something is, but once you do the bug fix is only needed once (or you have to add a new special case for that template) when it comes to testing with either system you have to test fully, the benifits of the multi templated design also have a determental effect on testing, any changes to the base code although it should fix bugs in all uses has to be fully retested, and you may have to add a special case for a type or two with cut'n'pasted versions you only have to retest the types you changes but changes are if there's a bug in the code it will be in all places so as mentioned above you've got more work to do. I prefer the multi template designs because bug fixed automatically propergate across the system and they tend to allow the user side of the template to be easier to use (at the expence of the library code being a little more involved)
Aug 10 2003
prev sibling parent Farmer <itsFarmer. freenet.de> writes:
"Carlos Santander B." <carlos8294 msn.com> wrote in
news:bh5nmm$1mt8$1 digitaldaemon.com: 

 (When template inheritance could be useful)
 Take a look at Farmer's implementation (in the postinc thread). He has 2
 templates MyFuncs (lines 108 and 125), and in each he has a class
 Stateful, both identical. I don't want to be annoying with this, but I
 think you understand that if that was the case for more and more
 templates, classes, functions, etc., it wouldn't be a simple task to
 keep the consistency across all of them. That's what I was trying to
 say. (Now, if I'm again using the wrong words, please excuse me.)
If I had used two template layers as Mike suggested, then there would be no duplicate code: template MyFuncs(Item) { // include appropriate print function alias instance _MyFuncs(Item).print print; class Stateful { uint size; void sumSize(Item v) { size+=v.size; } } } private template _MyFuncs(Item) { void print(Item v) { printf("%.*s\n",toString(v)); } } private template _MyFuncs(Item : Object) { void print(Item v) { printf("%.*s\n",v.toString()); } } Regards, Farmer.
Aug 11 2003