C vs. C++

R

REH

Ugh.  Just the fact that such a thing is allowed puts me off C++.

It's no different than you allocated memory in C and initializing an
object in it. It just allows it to be done for object's requiring
construction. Container classes make use of it to be able to construct
objects in the container's memory and destroy objects removed from the
container without have to constantly reallocate memory. It makes the
containers implementation more efficient. A C++ vector, for example,
guarantees it will never allocate more memory from the free store, and
long as the vector's capacity is not exceeded. Placement new makes
such a guarantee easy to implement, by being able to construct an
object at a given element of the vector's internal array, and to do so
in a portable way.

There are a lot of things C++ has to improve portability. For example,
unlike C, C++ has a portable mechanism for comparing unrelated
pointers. The next version of the standard will include portable
mechanisms for doing such things as memory fences and atomic
operations.

Of course, I get the feeling that you wouldn't change your opinion
even if it programmed itself while you slept. C is a great language,
but it's not the end-all-be-all of programming. At my job I use all of
C, but I also use a lot of C++ and Ada, plus various other tools that
suit my needs. I don't try to shoehorn every programming problem into
my favorite language. I use what's best (for whatever best means at
the time). One time it meant using VBScript (though I hate the
language), because it was the one scripting language I could guarantee
was one every machine it has to run on and had the necessary features
to do the job. Perl would have been a better choice, if I could have
made the same guarantees.

REH


REH
 
R

REH

And I'm totally confused as to where this "cast is essential" is
from. Since you generally use new from what I can remember and that
returns the reference to the correct type/class.

Small correction: it returns a pointer to an object, not a reference.

REH
 
R

REH

Virtually all data is integers, reals, or strings.
Complex languages blow up the number of types and the number of ways of
arranging the types. Then you need templates to try to control the mess.
So one type of complexity is addressed by adding another layer of
complexity. Sometimes it works, more often the human programmer cannot
easily cope with the extra layers of abstraction, and the program is harder
to debug than it would have been written in a simpler language.

And when you need to create containers of these three types of yours,
templates allow you to define a single set of functions that will
operate correctly on all of them regardless of type (integer, real, or
string, or something else), and regardless of the container (array,
linked list, or something else).

I find it very amusing that the one feature of C++ that people keep
using as an example of it's complexity is templates. Templates are not
that complicated, and they make a lot of thing much simpler. With a
simple template, I can define max/min functions which work correctly
on any type, and do not suffer the problems of a macro. And in only a
few lines of code. Plus, it is very type-safe and will only allow
objects of the same type to be compared.

Granted, templates can be--and have been--abused, but so can any
language features. I don't feel that's a valid comment on the
language, but on the programmer. Look at all power a simple pointer
gives you. It's much maligned, but an extremely useful thing.

REH
 
B

Ben Bacarisse

Dik T. Winter said:
Indeed, the featurelist is not even interesting. You can program complete
arithmetic in a language that only supports the Peano axioms. If you can
write functions (or operators) in that language you get complete arithmetic,
possibly a but more cumbersome (when operators can not be defined) or just
trivial. The speed will be a bit different, but that was not the
question.

I think you are talking about something slightly different. I
specifically chose examples of "things that can be expressed" that
can't, normally, be built from other mechanisms or at least if they
can, the effect is so complex as to defeat the benefit. That, to me,
is what expressiveness is about. Not what can be computed, but how
effectively it can be expressed.

Your example is of a language that can express arithmetic even though
it is not built-in because it can also express the notion of
abstracting a computation over those values -- i.e. it has functions
that take and return a representation of the values involved.

To illustrate the reverse, C can't easily express computations
involving functions because you can't create function values at run
time. This does not mean (as I know you know) that there is anything
you can't program in C, simply that there are some forms of
computation that can't easily be expressed.

Every feature that adds to the expressiveness has associated costs --
it may be hard to implement, it may make optimisation difficult, it
may just add to the difficulty of understanding the language -- so
that language design becomes a tricky balancing act. C has made, in
my opinion, one of the cleverest set of compromises to end up with a
very simple language that is highly expressive. C++ is more
expressive, but simply listing the things it can express directly that
C can't would not be interesting. One has also to consider the costs
or one is just listing features.

C++'s cleverness is to avoid run-time costs. The price in terms of
language complexity is quite high, though.

On balance, I'd take what C++ has to offer, but I've been using it
since it was "C with classes" and the complexity has been added
slowly. I've had about two decades to absorb it. I think I would
find it daunting if I were to start now.

<snip>
 
R

REH

Templates comprise a Turing-complete meta programming language. So they are
pretty powerful.

Yes, very powerful, and that ability was discovered by accident. It is
very useful in generic programming, but can become complex. Most
programs will never need such a thing. So, again, why condemn a very
useful feature, because it can be abused. Should we do away with
pointers or unions or recursion because of potential for abuse?
Say we want max and min functions for angles. How would you use templates to
capture that? How would you make the code break if someone naively tries to
apply it to angles, thinking it will do the right thing?

Yes, you could, if for your angles type, you told the language what it
means to relationally compare angles. If not, the compiler would
reject such a thing.

REH
 
B

Bartc

REH said:
I find it very amusing that the one feature of C++ that people keep
using as an example of it's complexity is templates. Templates are not
that complicated, and they make a lot of thing much simpler. With a
simple template, I can define max/min functions which work correctly
on any type, and do not suffer the problems of a macro. And in only a
few lines of code. Plus, it is very type-safe and will only allow
objects of the same type to be compared.

Is it possible to separate out Templates from C++ (perhaps losing some
features) and make them available to another language, in the same way as
the C preprocessor can be?

(I'm assuming here that Templates are just a sophisticated kind of macro.)
 
R

REH

Is it possible to separate out Templates from C++ (perhaps losing some
features) and make them available to another language, in the same way as
the C preprocessor can be?

(I'm assuming here that Templates are just a sophisticated kind of macro.)

If I understand your meaning, then I think you're wrong. Templates are
more than sophisticated macros, because they part of the compiler.
They understand types, where the macro are oblivious. The compiler
will not blindly generate code like a macro will. Everything has to be
there. If, as in the min/max example, the less than operator (or
function, or whatever your are using to compare the objects) is not
defined, the compiler would reject the template.

Yes, templates would work very well in another language. In C, though,
you would lose some of the power. C++ has other constructs that make
creating generic code easier because the syntax is equivalent. For
example, even primitive types like int, have constructors. So, a
template can use the constructor form to initialize an object, and not
disallow the use of primitive types.

REH
 
R

REH

You're familiar with angles surely?
Say I'm writing a 3D video game and considering whether to go for C or C++.
As part of the attempt to persuade me to go the C++ with templates route,
you provide some code that will allow min and max routines on angles. How
qwould you set about doing that?

I wouldn't try to persuade you. I'm not trying sell C++. Use C, if
wish. I just have read a lot of misconceptions, and flat-out incorrect
statements about C++.

I honestly don't fully understand what you're driving at. I believe
you are trying to trap me. I think you are assuming this(?):

int angle1, angle2;

If that's what you are thinking, then C++ doesn't know what these
integers mean, any more than C does. The less than operator would have
the same problem in both languages, as would min/max macros. The onus
is on the programmer--in BOTH languages--to do the right thing.

Now, there are a couple ways to handle this in C++: you could have a
template parameter that told the template how to do the compare, and
have it default to using the less than operator. So, you could
override it for individual case. You could define a unique type (an
enum, struct, or class would do) to serve as your angle, and define a
less than operator for it. Or, even don't define one, and simple let
the compiler reject it.

REH
 
R

REH

I don't understand the need for a constructor if you've got a simple int....

Because the code is generic. The template doesn't know that it is an
int. All the template requires (in this example) is that the object be
"default constructable" which just means the constructor takes no
parameters. For any int, this will initialize it to 0. If you could do
this, the code would have to be sensitive to whether the unknown type
is a primitive or not.

REH
 
I

Ian Collins

REH said:
Yes, templates would work very well in another language. In C, though,
you would lose some of the power. C++ has other constructs that make
creating generic code easier because the syntax is equivalent. For
example, even primitive types like int, have constructors. So, a
template can use the constructor form to initialize an object, and not
disallow the use of primitive types.
Perhaps a clearer example is user defined types having overloaded
operators. This enables basic generic algorithms like sorting to be
clearly implemented with templates. No need for casts to/form void* and
comparison functions. This in turn leads to another advantage:
performance. The comparison operator is visible to the compiler and may
be inlined.
 
R

REH

Perhaps a clearer example is user defined types having overloaded
operators.  This enables basic generic algorithms like sorting to be
clearly implemented with templates.  No need for casts to/form void* and
comparison functions.  This in turn leads to another advantage:
performance.  The comparison operator is visible to the compiler and may
be inlined.

I was going to use that very example, but I was afraid of starting a
"user-defined operators suck" argument.

REH
 
K

Kaz Kylheku

Virtually all data is integers, reals, or strings.

I disagree. Virtually all data is ones and zeros.

Integers versus reals versus strings is just a way of blowing up the
number of data types over ones and zeros.

There is no new semantic drama being played out, just syntactic sugar.

:)
Complex languages blow up the number of types and the number of ways of
arranging the types. Then you need templates to try to control the mess.
So one type of complexity is addressed by adding another layer of
complexity. Sometimes it works, more often the human programmer cannot
easily cope with the extra layers of abstraction, and the program is harder
to debug than it would have been written in a simpler language.

The debugging issues are different in different level languages: what kinds of
problems you look for, how you go about it, and what your tools are.

In general, the simpler the language, the more debugging you have to do
in those features of your program that provide the support that you
would get from a more complex language.

When the more complex languages are mature, they tend to provide good debugging
support for those features. Missing language features emulated in the program
rarely have debugging support at all, let alone good debugging support.

Sometimes standard language features do have poor debugging support. E.g. a
closed-source library function that you cannot step through in
the in the debugger except that the machine language level, and that you cannot
recompile for debugging support.
 
K

Kaz Kylheku

Templates comprise a Turing-complete meta programming language. So they are
pretty powerful.

I don't think that this Turing completeness has anything to do with the
power of templates as they are usually applied. It's something that was
discovered incidentally (as in a surprising, unintentional outcome of
the design) and leads to largely esoteric examples that have no practical
application.

Templates give power in their ordinary, use.

Why people use templates as an example in C++ discussions is not because
templates are complicated, but because they are the principal meta-programming
feature in C++. Nothing else in C++ performs user-defined syntax tree
transformation. Moreover templates have a deduction feature for figuring out
missing parameters, which is more sophisticated than the pattern matching in
overload resolution.

Templates perform some basic reasoning about the context of their application,
and write customized code for the situation. This is something that a human
being could do too, with a lot of error-prone labor that would have to be significantly reworked at every small change in the requirements.
Say we want max and min functions for angles. How would you use templates to
capture that? How would you make the code break if someone naively tries to
apply it to angles, thinking it will do the right thing?

There are answers to these questions, but they involve you in all sorts of
difficulties and hard design decisions.

These are better difficulties compared to the alternate difficulties you face
in solving the problem with no templates.
 
J

jacob navia

Kaz said:
Complexity has to exist somewhere. If you banish it from the programming
language, you push it into the programs. It's not an exact conservation law,
because a given amount of complexity in one place may translate into vastly
more complexity if it is relocated to another place, due to duplication of
effort.

The problem is not the necessary complexity tied to the application
but the unnecessary complexity tied to the use of an obscure programming
language

That is unnecessary complexity that adds nothing to the program but bugs.
C++ can manage certain complexities that are otherwise difficult in C.

As a rule:

language simplicity => program complexity

No. It may mean that the programmer must develop some routines
that *could* be part of the C standard library but they aren't.

The problem with C is that all development has stopped and it
has become a dead language. I have been discussing this problem
in this group for years, together with the comp.std.c, where
I have been met with the ususal: "If you want C++ go there".

All developments in C (specially the update of the standard
library that is hopelessly OBSOLETE by now) are stopped by the
attitude of many C community members that see any development
as an attack to their baby.

This leads to the situation where nobody develops a higher
level library for C. Then, of course, C will be criticized
as being "low level".
It helps to look at backwards. If you have large body of code written in a
complex programming language, and you want to simplify the programming
language, as a rule that will require adding reams of code to that existing
code to compensate.

No. In most cases the algorithm behind
list<int>
are not really complex at all and can be replaced without any greater
problem.

Every little thing you remove from the language will
potentially have an impact over broad areas of the existing code base,
potentially requiring reams of complexity to be heaped onto it.

Do you have any data to support that assertion? Supposing you replace
list<int>
with a linked list in C. You can use any of the several libraries
available. What complexity did you add?

Whatever /single/ thing you don't have in a language for taking care of some
responsibility translates to countless repetition of that responsibility.

No. It requires a little bit of coding effort that is payed off by
not having to care about the complexities of C++.
This is particularly true of language features that generate code. It's less
true of library features. If you take a function out of a library, you might be
able to just add that function to your program. You might have a big library
used by everyone in your your software organization, so you might be able to
just add it in one place even for many programs. But there are still other
organizations that will be similarly reinventing the function.

You might not like C++ templates, but what would have to be done to a C++
codebase that is based on templates, if templates were taken away, and how does
that task compare to the complexity of templates? What if the codebase is much
larger and more complex than the implementation of templates?

I am working in a solution of that problem. It is not the C++ way, but
the C way. "Trust the programmer" means that you open to the programmer
a window into the compiler itself. You can't imagine the SIMPLIFICATION
that that method provides. Instead of obscure templates you get REAL
compile time functions written not in an obscure functional language
like the language of boost metaprogramming but in C.

I am working in this since more or less a year, and I have a lot of
things working already. I will present it to the C/C++ community this
year.
 
K

Kaz Kylheku

You're familiar with angles surely?
Say I'm writing a 3D video game and considering whether to go for C or C++.
As part of the attempt to persuade me to go the C++ with templates route,
you provide some code that will allow min and max routines on angles. How
qwould you set about doing that?

First, we'd get together and discuss the semantics of what we mean by min and
max routines over angles. What are the issues and what are the requirements.
We would then think about how to represent angles, etc.
 
J

jacob navia

REH said:
I find it very amusing that the one feature of C++ that people keep
using as an example of it's complexity is templates. Templates are not
that complicated, and they make a lot of thing much simpler. With a
simple template, I can define max/min functions which work correctly
on any type, and do not suffer the problems of a macro. And in only a
few lines of code. Plus, it is very type-safe and will only allow
objects of the same type to be compared.

In the company I am working we are trying to replace all calls to the
max() macro with a call to our own macro since the template solution
requires identical types at both sides. If you write:
max(2,3.5)
the template solution will not work.

This means that a colleague of mine is working since 2-3 weeks making
hundreds of modifications to a huge C++ code base. Making max() a
template was a BIG MISTAKE.
 
I

Ian Collins

Malcolm said:
Virtually all data is integers, reals, or strings.
Complex languages blow up the number of types and the number of ways of
arranging the types. Then you need templates to try to control the mess.

Following on form your logic, most uses of templates are for integers,
reals, or strings.
So one type of complexity is addressed by adding another layer of
complexity. Sometimes it works, more often the human programmer cannot
easily cope with the extra layers of abstraction, and the program is
harder to debug than it would have been written in a simpler language.
The complexity is in the problem to be solved. The complexity in the
solution is shared between in the programming language and the code.
Templates offset some complexity from the programmer's code to the compiler.
 
K

Kaz Kylheku

Is it possible to separate out Templates from C++ (perhaps losing some
features) and make them available to another language, in the same way as
the C preprocessor can be?

Yes and no.

Yes because templates work purely statically in C++. They are not like Lisp
macros (which have the entire language at their disposal at compile time).
That is to say, the actions of templates are implicit, and not written in C++.
The template language doesn't require other C++ features like classes,
exception handling, etc.

No because you need other things besides templates in order to make
them work.

There are template classes of course, which don't make sense if you don't have
classes. In a C with templates, you could have template structs and
template functions.

The output of templates does depend on function overloading support. A
template function is a pattern generating variants of a function (possibly
after automatically deducing the template parameters). All those generated
variants have the same name, but different type signatures.

So you need overloading support in the rest of the compiler, and also in the
linkage model (name mangling or more direct support).

So templates could be added to C, if at the same time suport for overloaded
functions was also added.
(I'm assuming here that Templates are just a sophisticated kind of macro.)

Templates resemble macros when explicit instantiation is used. The
instantiation request supplies the arguments to the template parameters,
and the template expands right there.

They resemble macros somewhat less when template arguments are deduced. That's
a bit of sophistication above an explicit macro call.
 
K

Keith Thompson

jacob navia said:
In the company I am working we are trying to replace all calls to the
max() macro with a call to our own macro since the template solution
requires identical types at both sides. If you write:
max(2,3.5)
the template solution will not work.
[...]

It will work just fine if you write
max(2.0, 3.5)
or, more generally,
max((double)int_expr, double_expr)

Yes, it's a little more typing. Are you concerned about cases where
you don't know, at the point of call, what the types are and what type
one or both of them should be converted to?
 
K

Kaz Kylheku

Perhaps a clearer example is user defined types having overloaded
operators. This enables basic generic algorithms like sorting to be
clearly implemented with templates.

Generic algorithms over user-defined types requires only one thing:
user defined generic methods.

Overloaded operators are just syntactic sugar to connect operator
syntax with functions. They are not what makes the generic
algorithm implementation possible.
No need for casts to/form void* and
comparison functions. This in turn leads to another advantage:
performance. The comparison operator is visible to the compiler and may
be inlined.

The same could be done without overloading. You'd have an overloaded
compare function whose variants are inlined, and the variant that
handles ints would use the built-in < operator.

The sorting algorithm would make calls to compare.

Actually wrapping compare with a user-defined < operator is not
required to make the solution work, nor to make it inlined.
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top