What has C++ become?

J

James Kanze

The STL code is a fairly straightforward translation into the D
programming language:
import std.algorithm;
Key k;
Element[] v;
auto found = find!("k == a.getKey()")(v);
if (found == end(v))
doSomething(v, null);
else
doSomething(v, *found);
In this specific example, lisp is even higher level (ie.
more concise):
I'm not sure I agree with your definition of higher level
being more concise. Doesn't higher level mean more abstract?

In the context being considered (where "highest level" ==
"application"), a rough first approximation is that "higher
level" means that it depends on some "lower level". Lowest
level is thus the compiler with its constituant libraries and
the OS. Highest level is the function main().

Although this doesn't map directly to abstraction, it is
somewhat related: at the application level, you deal with very
concrete types: ClientOrder, Affectation, etc. Types that are
very far removed from the machine hardware, or even what the
language offers directly. At the lowest level, you'd probably
be talking about electrons, but of course, you don't go down to
that level in C++; for pratical purposes, in this group, the
lowest level is C++ and the OS API.

Pascal's point is, no doubt, that Lisp is further from the
actual hardware (and thus higher level) that is C++. At least
in this one particular case---I'm not convinced that it would
generalize to all cases. And I don't quite see how it is
relevant here.
 
N

Nick Keighley

James Kanze wrote:
 A difference between maybe 5 seconds, and a couple of minutes
[to compile]. Which is a very significant difference if you're
sitting in front of the computer, waiting for it to finish.
I love when compilation takes more then a couple of seconds: I
have extra time to think! Sometimes it ends with killing the
compilation and doing something else, rather then trying the
result.

Interesting development process.  I usually try to think before
editing, much less compiling.

he must be using an Agile methodology

:)
 
V

Vidar Hasfjord

This is, of course, totally ridiculous.  

Well, it seems there is confusion here stemming from two, quite
legitimate but different, uses of "high and low level" terminology. On
use is in describing system architecture layers (Kanzes' use) and one
is in describing abstraction levels (Roberts' use).

E.g. std::sort is at close to the highest possible abstraction level
for the algorithm it abstracts. Still it is probably used only at the
lower implementation layers of any system architecture.

See
http://en.wikipedia.org/wiki/High-level
http://en.wikipedia.org/wiki/Abstraction_(computer_science)

Regards,
Vidar Hasfjord
 
N

Noah Roberts

Vidar said:
Well, it seems there is confusion here stemming from two, quite
legitimate but different, uses of "high and low level" terminology. On
use is in describing system architecture layers (Kanzes' use) and one
is in describing abstraction levels (Roberts' use).

Notice what is said in the Robert C. Martin article I liked to and used
as support. He states that the abstraction/higher level code (my use)
should be in the application code (other use). In other words the uses
are not actually different.

http://www.objectmentor.com/resources/articles/dip.pdf
http://www.objectmentor.com/resources/articles/stability.pdf
E.g. std::sort is at close to the highest possible abstraction level
for the algorithm it abstracts. Still it is probably used only at the
lower implementation layers of any system architecture.

I never said that these STL routines were the highest level of
abstraction. They are specific algorithms and data container types.
Higher levels might make use of more abstraction that allows any
container to be used. These very well might make use of templates.

Kanze is trying to claim that template code belongs only in the "lower"
levels and not in "application code" and I'm trying to show that this
just isn't true. He's used as his backing to this argument that the STL
is low level code. I've tried to show that this also is not true, and I
think I've done a fairly good job of that.

STL objects and algorithms are relatively high level pieces of code.
They perform a set of abstract functionality that is not specific to any
particular data type until instantiated (and can even work with
polymorphic types with some wrapping). Unlike say operations like
strcmp or memset, which work at a low level on a particular data type
(raised only in the use of vague pointers), the templated nature of STL
operations allow them to work on any data type.

Dynamic polymorphism can be more abstract but static polymorphism can
also be quite abstract and can solve many problems at the *highest*
levels of your *application code*. It makes no sense to say that they
should only be used in low level development since they frankly don't
actually fit there too well. Low level is where you have specifics,
places where a particular non-abstraction is manipulated. This is not
what templates are. Chances are that your code will be more dynamically
than statically polymorphic but this does not mean that static
polymorphisms are for low level code nor that it isn't perfectly
appropriate in application code.

I would even go as far as saying that generic programming is a higher
level, more abstract AND higher in structure, than oop.
 
N

Noah Roberts

Pascal said:
Indeed. It is theorically possible to write a high level library in
C++. But strangely enough, it looks like it's so hard to do that it's
not done often... Ok, just nagging, there's Lpp.
http://www.interhack.net/projects/lpp/

What I'm saying is that you didn't actually use the find algorithm
differently. There is one key difference only and that is a consequence
of the language you are using only. That difference is that the lisp
version can return (), which is the same as returning 0 in C++. That is
possible because of lisp's fundamental list nature...all lists end in
(). In C++ it doesn't work for all container type, vectors for instance
should not return 0 for their end since that doesn't meet the
requirements of the iterator concept in the C++ language: namely that it
is not reachable from begin() with ++ operations.

This is what allowed you to avoid checking the end() iterator before
calling the do_something routine. To perform this, in C++, would
require losing some abstraction and thus getting lower in your level of
code.

In other words, the only, and I mean the only, difference between the
two pieces of code you supplied is that one is written in C++ and the
other in LISP. The C++ version is an abstraction that wraps up the
concepts within the language it is written in, the lisp version does it
the lispish way. The two versions of find_if are at the same level of
abstraction.

Now, that being the case, you could have used the ternary operator
and/or boost::lambda to put all that in one line of code if you really
wanted to, just as your use in lisp does. I for one don't happen to
like that style of coding all the time and until C++ comes out with
lambda expressions I don't encourage the use of them (boost::lambda is
not without problems). Pretty sure this is, in fact, on the way but
we'll see if they make it; I'm not on the committee I just saw them
working on it at boostcon.
 
J

James Kanze

Notice what is said in the Robert C. Martin article I liked to
and used as support. He states that the abstraction/higher
level code (my use) should be in the application code (other
use).

Which only makes sense: the application is the highest level, in
the sense I'm using the words.
In other words the uses are not actually different.
I never said that these STL routines were the highest level of
abstraction. They are specific algorithms and data container
types. Higher levels might make use of more abstraction that
allows any container to be used. These very well might make
use of templates.
Kanze is trying to claim that template code belongs only in
the "lower" levels and not in "application code" and I'm
trying to show that this just isn't true.

I'm not "claiming"; I'm constating. Templates, as implemented
by most compilers today, don't work well at the application
level. It's not a big problem, yet, because typically, most
polymorphism at the application level needs to be dynamic. The
need for templates is less.

Today, at least. Like most people, I'm intreged by the
possibilities of TMP. For the moment, however, it's not
generally used at the application level, and we can't really
experiment too much with it to determine whether it is relevant
or not at this level, because of the way most compilers
implement templates.
He's used as his backing to this argument that the STL is low
level code. I've tried to show that this also is not true,
and I think I've done a fairly good job of that.

You've not shown anything. The STL is extremely low level, in
this sense, since it is (formally) part of the compiler; it
depends on nothing else.

Perhaps it is a problem of definition. In this case, I'm not
arguing about the level of abstraction (although the STL is
pretty low level in this respect, as well); I'm arguing about
dependencies.

Actually, even dependencies, and low level vs. high, probably
aren't the issue. Stability is. Templates don't work in code
that isn't stable, because of the dependencies they introduce.
Application level code is normally the least stable; if the
application requirements change, you have to change it, and if
the application requirements don't change, you don't have to
change anything. The STL, as part of the compiler, is the most
stable---you don't ever change anything in the STL yourself, and
of course, if you change compilers---something you don't want to
do very often---you do a complete rebuild anyway.

Anyway, the fact remains that in well run shops developing large
applications, the use of templates is strictly limited to the
most stable, lower levels, and this is really where they are
most essential.
STL objects and algorithms are relatively high level pieces of
code. They perform a set of abstract functionality that is
not specific to any particular data type until instantiated
(and can even work with polymorphic types with some wrapping).

But they still expose far too many "details". When is an
iterator valid? It depends on the type of container.
Unlike say operations like strcmp or memset, which work at a
low level on a particular data type (raised only in the use of
vague pointers), the templated nature of STL operations allow
them to work on any data type.
Dynamic polymorphism can be more abstract but static
polymorphism can also be quite abstract and can solve many
problems at the *highest* levels of your *application code*.

Certainly. But that's not really the issue here. The issue is
that at the highest levels of application code---code which is
changing constantly---templates, as currently
implemented by most compilers---don't work. And at present,
it's not really an issue, because they're not that necessary.
Although TMP shows some promess of being applicable for certain
things at that level, the technology isn't stable enough or
mature enough that you'd want to use it yet.
It makes no sense to say that they should only be used in low
level development since they frankly don't actually fit there
too well. Low level is where you have specifics, places where
a particular non-abstraction is manipulated. This is not what
templates are. Chances are that your code will be more
dynamically than statically polymorphic but this does not mean
that static polymorphisms are for low level code nor that it
isn't perfectly appropriate in application code.
I would even go as far as saying that generic programming is a
higher level, more abstract AND higher in structure, than oop.

Which, of course, is silly, unless you redefine higher level to
mean something it has never meant.

In terms of *flexibility* (which I think is what you're really
talking about), there is the old argument of static vs. dynamic
typechecking. Languages like Smalltalk or lisp, which have
fully dynamic type checking, are more flexible than C++ or Java,
which do static type checking. This flexibility comes at a cost
in robustness, however; while people have done it, I'd be very
sceptical of writing a concrete application (as opposed to
prototyping) using a dynamically typed language. In the case of
C++ templates, we have a case of dynamically typed polymorphism,
but since the polymorphism is resolved at compile time, we do
not loose the robustness of compile time type checking. (On the
other hand, we do loose the flexibility of having it resolved at
run time. It's a different compromise.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,997
Messages
2,570,240
Members
46,830
Latest member
HeleneMull

Latest Threads

Top