On Monday, 3 March 2014 at 22:50:18 UTC, Frustrated wrote:
On Monday, 3 March 2014 at 18:46:24 UTC, Chris wrote:
I think the problem is not that people don't understand
templates in the sense that they are abstractions. The
question is whether there are loads and loads of use cases for
them.
It is irrelevant if there are loads and loads of use cases for
them. Just because people don't use something doesn't mean it
is useless.
Nobody ever said this.
to have to create a function every
This is a typical use case and always mentioned in tutorials.
The question is how many of these "typical" cases one
encounters while writing software.
Look at the STL library if you do't believe templates are
useful...
I think another problem with templates is that it is not
always clear what is abstracted. The type or the logic? Both?
In the above example the logic remains the same and is
reproduced by the compiler for each type. Sometimes the logic
can be abstracted for which type independence is important.
But I'm not sure if that can be called a template in the
purest sense. E.g. an algorithm that finds the first instance
of something might be different for each type (string, char,
int) and the "abstract" implementation has to differentiate
internally (if string > else if int > else if ...). But this
is no longer a template, or is it?
Both logic and types are abtracted. Even though the template
might use the same operator, the compiler must determine which
concrete operator to use.
The addition between the two abstract objects also requires an
abstract operator.
The great thing is, because the abstract logic is
identical("adding two things") makes the template actually
useful. If it wasn't we would have to specialize the template
for all the different possible binary combinations and then it
would defeat the simplification that abstract is suppose to
offer.
Purely philosophical remark: You're talking about the level of
how the compiler implements it. The logic (a+b) is not abstracted
but the same in every case. How the compiler has to deal with it
in every case is irrelevant for the concept of templates, because
it's the same as writing:
int add(int a, int b) { return a+b;}
int add(double a, double b) { return a+b;}
etc.
The the logical process is used when one looks at procedural
code and realizes that one can "simplify" it by using oop.
Templates give you the same power over oop that oop gives over
non-oop. But just because templates[oop] are available doesn't
mean you have to use it or it is always the best solution.
I use templates all the time. I create them to simplify some
task then put them in a library. For me, templates allow me to
streamline things that I couldn't otherwise do. Any time I feel
like something is being repeated a lot I automatically think
that a templates will help. I hate "copying and pasting" and so
I tend to use templates a lot.
I'm starting to do the same thing. But my experience (so far) has
been that abstraction goes only so far and a template only
covers, say, 2 cases instead of 4 and I have to write 2 separate
templates. Granted, in the old days, I would have written a class
that handles all four cases, so it saves me some coding. But in
may applications, templates are not really necessary. If you
write a program that deals with strings, most functions will take
a string as an input and return a string (or an array of strings)
as an output. This is at least my experience. If code is repeated
all over again, you put it into a separate
function/method/class/struct anyway. I find myself using ranges
quite a lot.
One of the main uses of templates is compile time type safety.
This is necessary with oop because oop allows one to create
types at compile time. Hence, the need to be able to make your
oop "safe" is a natural step and templates help you accomplish
that.
e.g., Array's of objects vs Array's of a Type. One is much
safer, informs the about what your intentions are so it can
make better informed decisions.
e.g., Array!Type allows the Array to determine if the Type
supports certain things at **compile time**. Array!Object can't
do this at compile time.
Yes, we have useful template constraints (isInputRange etc).
If you can't see the benefit of Array!Type vs Array!Object then
you are beyond help. (this is not to say Array!Object is always
useless, but it is the most generic you can get and the
compiler can do little to help the situation)
I'll give you a simple example: One could create an Array type
that allows one to traverse the array in a multitude of ways.
Suppose the objects stored by the arrays are arrays themselves.
If the Array is templated it could easily figure this out and
create an iterator that iterates over the sub-array(calling its
iterator).
This way one could easily display a flat list of the array [of
arrays [of arrays ...]]. Because the Array type could figure
out all this at compile time it would be way more efficient
than having to use run-time reflection to determine of the
object is an array and if it has the iterator. (it would also
be easier to code)
Basically you have the choice:
------------ <- "template" way of thinking (more general than
oop)
-------- <- Oop way of thinking (more general than procedural)
----- <- procedural way of thinking... "Old School"
- <- Punch Cards
(it's not quite that simple as templates or more of an offshoot
of oop)
Maybe that's why it is so hard to see the benefits of templates,
because many cases (of abstraction) are already covered by OOP. I
like templates, but I'm not sure if they are as useful as D's
ranges. Ranges and component programming handle the ubiquitous
input>filter>output paradigm present in every program and help to
break down the program's logic into digestible chunks, a logic
you cannot just copy and paste (but you can reuse the chunks). In
cases where you use templates, you can also get away with copy
and paste and replace "int" with "double".
If you are thinking at the template level then you will know
when to use templates. If you are thinking at the oop level,
you always go for your oop hammer(duh, cause everything looks
like an oop nail). If you are thinking at the procedural level
then you always try to solve problems in the procedural way.
I prefer the top-down approach... Call me a racist but I just
hate punch cards.