www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Templates everywhere

reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
I was looking at some of my code today, I was surprised to see it was almost
100% templated: functions, mixin, structs, 'real' templates, what have you.
Apart from main, what I write these days is full of (U,T...) if () {} and
templates of templates of templates.

That's quite an evolution, because when I discovered D 2 years ago coming from
C++, I only used foreach and dynamic arrays. In C++, I never had any reason to
create my own templates and couldn't wrap my head around anything template-y
more complicated than 'containers of T'.

Today I think in templates (well, at least I try to...). So:

1- thanks Walter for opening new vistas to me. Doing templated code in D is so
fun and powerful that you transformed forever the way I look at problems.
2- Do other have a similar evolution?


  Philippe
Mar 14 2010
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Philippe Sigaud" <philippe.sigaud gmail.com> wrote in message 
news:hnitl9$1kpg$1 digitalmars.com...
I was looking at some of my code today, I was surprised to see it was 
almost 100% templated: functions, mixin, structs, 'real' templates, what 
have you. Apart from main, what I write these days is full of (U,T...) if 
() {} and templates of templates of templates.

 That's quite an evolution, because when I discovered D 2 years ago coming 
 from C++, I only used foreach and dynamic arrays. In C++, I never had any 
 reason to create my own templates and couldn't wrap my head around 
 anything template-y more complicated than 'containers of T'.

 Today I think in templates (well, at least I try to...). So:

 1- thanks Walter for opening new vistas to me. Doing templated code in D 
 is so fun and powerful that you transformed forever the way I look at 
 problems.
 2- Do other have a similar evolution?
"Do other have a similar evolution?" As far as D specifically, the only evolution in me I can think of is this nice habit of being able to deal with code without getting absolutely fed up every three minutes (I had come from C++). It has also gotten me in the habit of certain good practices (like generic programming, for instance) which I [try to] bring with me as much as possible when I have to use a lesser langauge. I have had other things in the past though. When I first moved from BASIC to C (forever ago) I couldn't understand the usefulness of pointers (all the examples I saw in books seemed to do nothing more than create a redundant alias for a varaible that already existed in the same scope). Then I read some books about game development (on DOS), which involved a lot of storing data in buffers. That got me to understand how (at least in C) an array is just a pointer to a buffer but with prettier syntax, and then it all finally clicked.
Mar 14 2010
parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Mar 14, 2010 at 19:37, Nick Sabalausky <a a.a> wrote:


 I have had other things in the past though. When I first moved from BASIC
 to
 C (forever ago) I couldn't understand the usefulness of pointers (all the
 examples I saw in books seemed to do nothing more than create a redundant
 alias for a varaible that already existed in the same scope). Then I read
 some books about game development (on DOS), which involved a lot of storing
 data in buffers. That got me to understand how (at least in C) an array is
 just a pointer to a buffer but with prettier syntax, and then it all
 finally
 clicked.
I must have had bad experiences with pointers, because even now I cringe whenever I use one. I get the feeling I'm walking on ice, or something. That's strange because they were almost the first thing they taught me in CS courses a long time ago. You'd think I'd get used to them. Eh, when I use string mixins in D, I feel dirty, as if I was cheating somehow. Like, using cheat codes or something. I do not have this impression when doing macros in Lisp. Philippe
Mar 14 2010
prev sibling next sibling parent reply Walter Bright <newshound1 digitalmars.com> writes:
Philippe Sigaud wrote:
 1- thanks Walter for opening new vistas to me. Doing templated code
 in D is so fun and powerful that you transformed forever the way I
 look at problems.
Years ago, although I had implemented templates for C++, I didn't "get" them. Not at all. I didn't even plan to put templates in D, because they seemed overly complex, ugly, and had little value. It was pretty obvious, though, that the C++ community did get templates and did find them very useful. Something was wrong with my perception. I eventually realized that what was preventing me from understanding C++ templates was the syntax. Change the syntax, and what is happening suddenly becomes obvious. ======= C++ ========= template<class T> class Foo { T member; }; ======= D =========== class Foo(T) { T member; } ===================== Yes, it looks like a trivial change, and perhaps it is. But it makes a world of difference, because it now looks like something I do get - a parameter list to something. I had another epiphany from watching Scott Meyers give a presentation about an application for templated type lists in C++. Nearly the full hour was spent detailing a titanic struggle with the syntax. I suddenly realized that the whole presentation would have been over in 5 minutes if the syntax of type lists was simply that of an array of types. We already understand arrays of values, so why should an array of types be any different? It isn't the concept or application of templates that is hard. It's the C++ syntax for them that's hard. It's hard in C++ because when they were designed, little was known or understood about what templates were good for and how they should be used. Now that we do know, we can make a much more straightforward design.
Mar 14 2010
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Walter Bright:

Years ago, although I had implemented templates for C++, I didn't "get" them.
Not at all.<
It isn't the concept or application of templates that is hard. It's the C++
syntax for them that's hard. It's hard in C++ because when they were designed,
little was known or understood about what templates were good for and how they
should be used. Now that we do know, we can make a much more straightforward
design.<
I agree that D syntax makes templates simpler (and the semantics too has being cleaned up), and I like them in D. What's the purpose of templates in D? I think they have few main purposes: 1) Allow for type-safe compile-time genericity for collections and algorithms. 2) Perform some kind of usually simple "processing" on types, for example to determine what's the output type given two different input types. So types can be seen as compile-time variabiles for templates. Such processing is often related to the first purpose. 3) They can be used to perform compile-time computations on variables, for example to fill a data structure at compile-time. This is useful, but much less useful than the first two purposes of templates. Today in D this can often be done by CTFE that is getting better and better (thanks to Don too), so often today in D it's bad to use templates for this purposes. CTFE functions can be templated, so they can sometimes do what pure templates can do over types, with a much better syntax. templates, their purpose is mostly the first one in my list. Being less powerful they can (in theory) keep the language simpler to learn and use (in specify a collection to be covariant, contravariant, etc). So can explicit templates be "removed" from a C++/D-like language, and replaced by simpler generics, plus CTFE, plus a variable type (that is used at compile-time only by CTFE functions) that can contain a type? (Note that the end result is more or less the starting point. It's mostly a syntax shuffle). If I am not saying silly things, then the end result is a language with a semantics similar of D (it can do the same things), but with a little simpler syntax, because for the eyes of the programmer it contains functions only (plus classes, structs, etc). Bye, bearophile
Mar 14 2010
parent bearophile <bearophileHUGS lycos.com> writes:
Sorry, missed a small piece:

Walter Bright:
Years ago, although I had implemented templates for C++, I didn't "get" them.
Not at all.<
This is incredible. Thank you for this information :-) Bye, bearophile
Mar 14 2010
prev sibling next sibling parent reply Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sun, Mar 14, 2010 at 21:29, Walter Bright <newshound1 digitalmars.com>wrote:

 Philippe Sigaud wrote:

 1- thanks Walter for opening new vistas to me. Doing templated code
 in D is so fun and powerful that you transformed forever the way I
 look at problems.
Years ago, although I had implemented templates for C++, I didn't "get" them. Not at all. I didn't even plan to put templates in D, because they seemed overly complex, ugly, and had little value.
That's interesting to know that you could implement templates, without understanding them. I eventually realized that what was preventing me from understanding C++
 templates was the syntax. Change the syntax, and what is happening suddenly
 becomes obvious.
 (snip)
 Yes, it looks like a trivial change, and perhaps it is. But it makes a
 world of difference, because it now looks like something I do get - a
 parameter list to something.
That's my first 15' with D right there, Walter. It may be due to my not knowing what 'template' means in English at the time I was exposed to them in C++. But reading the D docs, it became clear that they were just 'potential code', waiting to be created, with parameters governing what could happen.
 I had another epiphany from watching Scott Meyers give a presentation about
 an application for templated type lists in C++. Nearly the full hour was
 spent detailing a titanic struggle with the syntax. I suddenly realized that
 the whole presentation would have been over in 5 minutes if the syntax of
 type lists was simply that of an array of types. We already understand
 arrays of values, so why should an array of types be any different?
Seconded, and thanks again for making that accessible. I was looking at Boost MPL (Meta-Programming Library) a few days ago, and thinking "How complicated the C++ syntax makes all this". I consider the MPL one of the most impressive part of Boost, but I don't think I'll ever use it. I have trouble extracting the intent among all the syntactic noise. Whereas in D, the first time I read some of Andrei's templates, (something akin to staticMap!(Unqual, Types)) the meaning was clear. The third 'leg' on which D templates rest is the alias parameters. I can have access to any symbol, including other templates? Oh yes! Philippe
Mar 14 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Philippe Sigaud wrote:
     Years ago, although I had implemented templates for C++, I didn't
     "get" them. Not at all. I didn't even plan to put templates in D,
     because they seemed overly complex, ugly, and had little value.
 
 That's interesting to know that you could implement templates, without 
 understanding them.
I think of it like a race car builder. I can build the cars, but I can't drive them worth squat. We are very fortunate, however, to have Andrei on board who literally wrote the book on how to drive them!
 The third 'leg' on which D templates rest is the alias parameters. I can 
 have access to any symbol, including other templates?  Oh yes!
In C++, these are called "template template parameters". It took me a long time to figure out what the point to template template parameters was, and then I wondered at the arbitrary restriction that they must be templates. Remove the restriction, and voila! Much more power! (And a much simpler explanation of them, too.)
Mar 14 2010
prev sibling parent reply Bane <branimir.milosavljevic gmail.com> writes:
 ======= C++ =========
 template<class T> class Foo
 {
      T member;
 };
 ======= D ===========
 class Foo(T)
 {
      T member;
 }
 =====================
 
 Yes, it looks like a trivial change, and perhaps it is. But it makes a 
 world of difference, because it now looks like something I do get - a 
 parameter list to something.
Fucking beautiful. I finally get it.
 I had another epiphany from watching Scott Meyers give a presentation 
 about an application for templated type lists in C++. Nearly the full 
 hour was spent detailing a titanic struggle with the syntax. I suddenly 
 realized that the whole presentation would have been over in 5 minutes 
 if the syntax of type lists was simply that of an array of types. We 
 already understand arrays of values, so why should an array of types be 
 any different?
 
 It isn't the concept or application of templates that is hard. It's the 
 C++ syntax for them that's hard. It's hard in C++ because when they were 
 designed, little was known or understood about what templates were good 
 for and how they should be used. Now that we do know, we can make a much 
 more straightforward design.
They say you understand stuff only after you make it, not before.
Mar 14 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Bane wrote:
 ======= C++ =========
 template<class T> class Foo
 {
      T member;
 };
 ======= D ===========
 class Foo(T)
 {
      T member;
 }
 =====================

 Yes, it looks like a trivial change, and perhaps it is. But it makes a 
 world of difference, because it now looks like something I do get - a 
 parameter list to something.
Fucking beautiful. I finally get it.
Ya know what's funny? I had to go and double check that the C++ syntax above was correct. Didn't have to do that for D.
Mar 14 2010
next sibling parent Bane <branimir.milosavljevic gmail.com> writes:
Walter Bright Wrote:

 Bane wrote:
 ======= C++ =========
 template<class T> class Foo
 {
      T member;
 };
 ======= D ===========
 class Foo(T)
 {
      T member;
 }
 =====================

 Yes, it looks like a trivial change, and perhaps it is. But it makes a 
 world of difference, because it now looks like something I do get - a 
 parameter list to something.
Fucking beautiful. I finally get it.
Ya know what's funny? I had to go and double check that the C++ syntax above was correct. Didn't have to do that for D.
D's example has look and feel of D, so it's intuitive. C++'s example may have l'n'f of C++, but it don't help because its ugly as crap by default and order of things in it make my eyes bleed and brain hurt. I hate <>. I like them only in XHTML.
Mar 15 2010
prev sibling parent reply Max Samukha <spambox d-coding.com> writes:
On 15.03.2010 3:42, Walter Bright wrote:
 Bane wrote:
 ======= C++ =========
 template<class T> class Foo
 {
 T member;
 };
 ======= D ===========
 class Foo(T)
 {
 T member;
 }
 =====================

 Yes, it looks like a trivial change, and perhaps it is. But it makes
 a world of difference, because it now looks like something I do get -
 a parameter list to something.
Fucking beautiful. I finally get it.
Ya know what's funny? I had to go and double check that the C++ syntax above was correct. Didn't have to do that for D.
Though I love D's templates: 1. People tend to throw them in where a runtime solution would suffice. One example is an overload of 'clear' in the D runtime: void clear(T)(T obj) if (is(T == class)) { auto defaultCtor = cast(void function(Object)) obj.classinfo.defaultConstructor; version(none) // enforce isn't available in druntime _enforce(defaultCtor || (obj.classinfo.flags & 8) == 0); immutable size = obj.classinfo.init.length; static if (is(typeof(obj.__dtor()))) { obj.__dtor(); } auto buf = (cast(void*) obj)[0 .. size]; buf[] = obj.classinfo.init; if (defaultCtor) defaultCtor(obj); } Since the function uses runtime information (except for the destructor), it is absolutely unnecessary to instantiate the template for each concrete class type. A more severe problem with the code above, unrelated to templates, is that base class destructors are not called. Here is a non-template implementation that should fix the problems (it is a template but only formally): void clear(Dummy = void)(Object obj) { auto ci = obj.classinfo; auto defaultCtor = cast(void function(Object)) ci.defaultConstructor; version(none) // enforce isn't available in druntime _enforce(defaultCtor || (ci.flags & 8) == 0); immutable size = ci.init.length; auto ci2 = ci; do { auto dtor = cast(void function(Object))ci2.destructor;; if (dtor) dtor(obj); ci2 = ci2.base; } while (ci2) auto buf = (cast(void*) obj)[0 .. size]; buf[] = ci.init; if (defaultCtor) defaultCtor(obj); } BTW, I do think that base class destructor calls not compiled directly into derived class destructors is a mistake. 2. Templates impose functional style on programmers (see Bartosz's rant at http://bartoszmilewski.wordpress.com/2009/10/21/what-does-haskell-have-to-do-with-c/).
Mar 15 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Max Samukha wrote:
 Here is a non-template implementation that should fix the problems (it 
 is a template but only formally):
Thanks, I've incorporated it.
Mar 15 2010
prev sibling next sibling parent reply Jason House <jason.james.house gmail.com> writes:
Philippe Sigaud Wrote:

 Today I think in templates (well, at least I try to...). So:
 
 1- thanks Walter for opening new vistas to me. Doing templated code in D is so
fun and powerful that you transformed forever the way I look at problems.
 2- Do other have a similar evolution? 
I started with a basic comfort with templates and generalizing code, but have taken things farther with D. I recently started ripping some templates out because my code was getting ugly. What I'm currently wishing for is templated modules... module foo(T,U,V); class bar // Implicit (T,U,V) { } module x; import foo!(T,U,V) bar b; // Not messier bar!(T,U,V) b It's a small bit of syntactic sugar, but for certain constructs, it can make a world of difference. I wonder if others would also want that.
Mar 14 2010
parent Walter Bright <newshound1 digitalmars.com> writes:
Jason House wrote:
 Philippe Sigaud Wrote:
 
 Today I think in templates (well, at least I try to...). So:
 
 1- thanks Walter for opening new vistas to me. Doing templated code
 in D is so fun and powerful that you transformed forever the way I
 look at problems. 2- Do other have a similar evolution?
I started with a basic comfort with templates and generalizing code, but have taken things farther with D. I recently started ripping some templates out because my code was getting ugly. What I'm currently wishing for is templated modules... module foo(T,U,V); class bar // Implicit (T,U,V) { } module x; import foo!(T,U,V) bar b; // Not messier bar!(T,U,V) b It's a small bit of syntactic sugar, but for certain constructs, it can make a world of difference. I wonder if others would also want that.
module foo; template foo(T,U,V) { ... your module's declarations ... } should do it.
Mar 14 2010
prev sibling parent reply Eldar Insafutdinov <e.insafutdinov gmail.com> writes:
Walter Bright Wrote:

 Max Samukha wrote:
 Here is a non-template implementation that should fix the problems (it 
 is a template but only formally):
Thanks, I've incorporated it.
Thanks for that, but what about the other issues, why does this function have to be a template? Why does calling __dtor doesn't call base class destructors(as it is done in C++)?
Mar 15 2010
parent reply Walter Bright <newshound1 digitalmars.com> writes:
Eldar Insafutdinov wrote:
 Walter Bright Wrote:
 
 Max Samukha wrote:
 Here is a non-template implementation that should fix the problems (it is
 a template but only formally):
Thanks, I've incorporated it.
Thanks for that, but what about the other issues, why does this function have to be a template?
So it works with other types, though that isn't implemented.
 Why does calling __dtor doesn't call base class destructors(as it is done in
C++)?
Doing it that way is non-trivial, and I was in a hurry to get the system working. Class destructors are rarely used in D, so doing it the simple way is not a performance issue. Destructors for structs, however, are done the more complicated (and more performant) way because they need to be more efficient.
Mar 15 2010
parent Eldar Insafutdinov <e.insafutdinov gmail.com> writes:
Walter Bright Wrote:

 Eldar Insafutdinov wrote:
 Walter Bright Wrote:
 
 Max Samukha wrote:
 Here is a non-template implementation that should fix the problems (it is
 a template but only formally):
Thanks, I've incorporated it.
Thanks for that, but what about the other issues, why does this function have to be a template?
So it works with other types, though that isn't implemented.
This code: ------- void clear(Dummy = void)(Object obj) { pragma(msg, "template instance: Object clear"); } void clear(T)(ref T obj) if (!is(T == class)) { pragma(msg, "template instance: " ~ T.stringof ~ " clear"); } class Boo {} class Foo {} struct Bar {} struct Baz {} void main() { auto boo = new Boo; auto foo = new Foo; Bar bar; Baz baz; clear(boo); clear(foo); clear(bar); clear(baz); } ------- outputs during compilation: template instance: Object clear template instance: Bar clear template instance: Baz clear Isn't that what you need?
 
 Why does calling __dtor doesn't call base class destructors(as it is done in
C++)?
Doing it that way is non-trivial, and I was in a hurry to get the system working. Class destructors are rarely used in D, so doing it the simple way is not a performance issue. Destructors for structs, however, are done the more complicated (and more performant) way because they need to be more efficient.
Thanks for the clarification. This is something I know little about, so I can't argue here.
Mar 15 2010