Possible solution to template bloat problem?

H. S. Teoh hsteoh at quickfur.ath.cx
Tue Aug 20 12:09:48 PDT 2013


On Tue, Aug 20, 2013 at 08:25:59PM +0200, Ramon wrote:
[...]
> My main point wasn't anti-D (although I still don't like to
> advertise generics when actually delivering templates and mechanisms
> to implement generics oneself) but a completely different one:
> 
> Sometimes I just want (or feel needing) to go fully OO and, at the
> same time, have the compiler take care of the nitty gritties. This,
> in fact, is a rather humble position; I have learned in many years
> that, no matter how smart we are, we introduce bugs and problems
> into our code because we are humans. I've learned the hard way that
> there are things computers simply do better and more diligently than
> we humans.

Actually, on this point, I think D can be improved. As John Colvin
suggested, we should collect the most common and useful OO patterns that
provide this kind of runtime polymorphic genericity and put them into
the standard library (std.patterns was suggested), so that you don't
even have to write this stuff yourself. Then maybe you will feel better
about D being advertised as "generic". :)


> And there is another point.
> 
> Nowadays, we happily use gigantesque GUI systems, we gladly put 3
> config parameters into an XML file and we happily consider 600k
> lines sorce code adequate for, say, an audio player based on some
> insane gobject system ...
> 
> On the other hand we do have serious qualms to increase program size
> by, say, 5% in an application that typically runs on a 4 core
> processor with 8GB RAM. This strikes me as ... uh ... strange.
> 
> And we *do get* something, possibly something vital, for those 5%
> code size increase, namely code that is easier to understand and to
> maintain, easier to extend and less buggy.

Actually, I think there's a lot to be said about reducing *source* code
size, in order to keep things maintainable. But more on this below.

OTOH, there are also advantages to keeping *machine* code size smaller
-- if your program (or the resident part of it) can fit completely
within the CPU cache, it will run *much* faster than if the CPU has to
keep swapping code pages in/out because your program is too big. This
issue is kinda hard to address at the high-level, though, because
although a runtime polymorphic approach will produce smaller machine
code (no code duplication), it also has poorer locality, because of all
the layers of indirection (the CPU has to keep the vtables and methods
of diverse objects in cache). A template approach has the disadvantage
of larger code size (due to code duplication), but it has better
locality because of less indirection -- it's easier for the CPU to fit
the code/data for inner loops within the cache than if you need to have
a vtable here, a method there, etc.. How all of this actually balances
out in practice isn't something easy to reason about, and is probably
highly sensitive to fine-tunings and specific use-cases.


> I'm not sure that Prof. Meyers no compromises attitude is always
> good. After all, life is a series of trade offs and compromises. I
> am, however, pretty sure that template systems tend to be messy and
> complicated - and therefore bound to be error prone.
> 
> 25 years ago I would have defended any weirdness; the harder and
> stranger the better. Meanwhile I have learned that readability often
> is considerably more important than ease of writing and that some
> compromises seem cheap but turn out to be very expensive later on.

I'm just guessing here, but I suspect maybe your perceptions have been
colored by the way C++ templates turned out? I've a strong C/C++
background, and IME, C++ templates do in fact turn out really messy and
hard to maintain. However, in my understanding, the problem isn't really
with the fact of a template system itself, but rather the way C++
implements it. To be fair, when C++ templates were first introduced,
they were only intended to fill the role of what today's Java/C#
generics do; the *other* usages of C++ templates were emergent behaviour
that was discovered after the fact. As a result, C++'s implementation
choices for templates didn't have the advantage of 20/20 hindsight, and
so it turned out to be really messy to maintain.

D's template system, OTOH... I have to admit that it took me a while to
get used to it, but after having used it for a couple o' years now, I
have nothing but praise for it. First and foremost, the syntax is far
saner than in C++, and, thanks to 20/20 hindsight, it was designed to
support the kind of emergent behaviour of C++ templates that C++ was
never designed to support. This, coupled with other niceties of D
design, CTFE, static if, signature constraints, and a few simple
innovations (but with profound consequences) like eponymous templates,
makes D's template system truly something to be reckoned with. It's
extremely powerful, very versatile, and yet it is *readable*!! In fact,
it is so readable that I have no qualms recommending people to read the
Phobos standard library's source code. You will not find the kind of
opaque unreadably terse convoluted hacks that, say, C/C++ is full of.
Instead, you'll find code exactly of the same kind that you'd write in
your own programs -- nice, clean, readable. Try it sometime. It's quite
an enlightening experience. :)

So, to answer your statement about ease of writing vs. readability, I'd
say, what about *both*? While D is certainly not perfect in this regard,
I haven't seen anything comparable among the languages that I know so
far.  D's template system makes code very easy to write, *and* easy to
read.  I honestly have no more appetite for C/C++ after learning D;
there is just no comparison.

For instance, in C, the most straightforward way to write code is
actually the wrong way -- you end up with memory leaks, unchecked error
conditions, and all sorts of such issues. Optimized C code, as I'm sure
you know very well, is basically a terse blob of unreadable symbols,
where changing a single character could break the entire program. In
C++, the most straightforward way to write code is, fortunately, correct
for the most part -- but usually slow and unoptimized. Optimized C++
code unfortunately looks not too much different from the unreadable blob
of optimized C code (and sometimes worse, if you have templates in the
mix).

In D, however, it's actually possible to write code that's very easy to
read, yet fully optimized.  D is almost unique in allowing you to write
code that reads like a textbook example, yet is actually carefully
optimized for maximum performance. You can actually write readable code
that's used for production software! D's standard library, Phobos, is a
shining example of this. (On the contrary, all my experiences of
production C/C++ code involve nasty hacks, inscrutable optimizations,
and needlessly fragile poor designs, that make me wonder about career
changes.)


[...]
> Thanks to your friendly, patient and constructive answer I'm feeling
> that while D isn't perfect it's quite close to it and, more
> importantly, it at least offers  guys like me what I consider
> important, if at a price. So what.
[...]

Well, I think we can reduce this price. :) As I mentioned earlier, we
should collect the most common and useful OO patterns that allow you to
write runtime generic code easily, and put them into the standard
library so that people like you can have your cake and eat it too. I
think D is up to the task. :)


T

-- 
English has the lovely word "defenestrate", meaning "to execute by
throwing someone out a window", or more recently "to remove Windows from
a computer and replace it with something useful". :-) -- John Cowan


More information about the Digitalmars-d mailing list