Thread overview | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
August 09, 2003 more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
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 |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander B. | "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). |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | "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 |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander B. | > 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)? |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander B. | "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(); } |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Matthew Wilson | "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 ); |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | 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 ); > > > |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | | "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 |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander B. | "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) |
August 10, 2003 Re: more templates (and a bit covariance) | ||||
---|---|---|---|---|
| ||||
Posted in reply to Mike Wynn | "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 |
Copyright © 1999-2021 by the D Language Foundation