comp.lang.ada
 help / color / mirror / Atom feed
From: Mark Lundquist <mark@rational.com>
To: Alexander Van Hecke <alexke@hotmail.com>
Subject: Ada vs. C/C++ (was re: bitwise something-or-other)
Date: 2000/01/21
Date: 2000-01-21T00:00:00+00:00	[thread overview]
Message-ID: <388905E0.81FEFBC5@rational.com> (raw)
In-Reply-To: 38836CF2.AB738B8B@hotmail.com

Alexander Van Hecke wrote:

>> Ada makes creating and using abstractions easier than C (packages for
>> encapsulation and information hiding; private types for information
>> hiding).
>
> Would you agree that C++ is just as good in that as Ada.

Well, I wouldn't agree!

I find C++ a lot more awkward and primitive.

> Don't forget that
> ANY C++ code can be easily translated into C?

I'm not sure what you mean.  If you mean that a translation program can do it,
so "it's as easy as invoking the translator", then your observation is true,
but irrelevant.  Right?  (Just think -- a compiler transforms an HLL into
machine code, just as cfront transforms C++ into C.  What would you think if
someone claimed this fact in support of an argument that coding an equivalent
program in machine code is no harder than writing the high-level language
program?)

If, on the other hand, you mean that given any C++ construct (e.g. a class),
it's just as easy to program the C equivalent, then I doubt you can really be
serious!  Have you ever actually looked at the C text produced by cfront?  Can
you really say you'd just as soon write that yourself?   For instance, C++ has
its VPTR/VTABLE crap, which hides your C callback stuff.  Don't you think
there's some benefit in not having to code that yourself?  The point isn't
that you *can't* do that in principle... no one is claiming that!  The point
is, who'd want to?  C++, despite its flaws, was invented for a reason.  And as
much as I'd rather use Ada than C++, I'd still rather use C++ than C.  This is
the whole purpose of higher-level languages, to take programs that are in
principle writable by someone with unlimited patience, unlimited time, and
perfect memory and record-keeping, and make them actually writeable by real
people!  The C level of abstraction is OK for little things, but it doesn't
scale up.  You can write big things in C -- with a lot of effort and pain.
C++ actually does give the programmer a higher view of programming than C, in
certain areas.

It's all about the level of abstraction you get to work in.

> For that matter, everything else you mentioned (namespace control, (easy)
> generics, exceptions and exception handlers, typing) is easily achieved in
> C++ (and thus C).

Your line of reasoning seems to be:

1) Ada and C++ are equivalent
2) C++ and C are equivalent, because you can translate C++ to C
3) Therefore, Ada and C are equivalent!  ("Ada feature X is 'easily achieved'
in C")

You seemed to take it for granted that anyone should concede (1), but those
who really know both Ada and C++ will be able to tell you all the ways in
which that is so wrong!  Ada is not C++ with better syntax.

As for (2), as I discussed above, the argument from translatability is
specious.  The translation in question is not transliteration, it's expressing
higher-level abstractions in terms of lower-level ones.  When you move up and
down the "abstraction level continuum", you don't get to use the
"translatability" argument, because you're trying to apply it with regard to
expressive power when it's only relevant to operational equivalence, which is
already assumed...  Am I makin' sense here?

> As I have said already a few times, and as I said in my original post : I
> THINK IT'S A NICE FEATURE OF ADA THAT YOU CAN WRITE READABLE CODE, BUT
> THAT
> DOES NOT NECESSARILY MEAN THAT THE LANGUAGE IS MORE POWERFUL!

Once again, nobody is saying that there are programs that you can write in Ada
that you can't write in some other language.  If this is what you're arguing
against, it's a straw-man argument.  The whole Turing-equivalence thing is
kind of something that Everybody Knows --  I think you can safely assume that
when someone claims that Ada is "more powerful" in some way, this is not what
they mean!  Yet that appears to be, from your "translation" argument, just
what you are arguing against...

The 'readability' thing always sounds like a superficial, syntax-level kind of
concern ("You say, 'tomato', I say...").  And certainly there's an aspect of
that, from the relatively inconsequential, like curly braces vs.
"begin...end", to stuff that makes more of a difference.  While
human-engineering at the syntax level is important, I don't think anyone is
going to say that getting it right results in huge gains in
productivity/reliability/whatever.  But the differences between Ada and
C/C++ run much deeper than this.

When an Ada advocate says things like "Ada is designed to be readable", they
are using the term "readable" in a way that doesn't really do justice to the
concept.  What they actually mean is that the source text lends itself to a
level of deep understanding of the programmer's intent.  For instance, the
"contract model" can result in a lot more information for the programmer who
is reading the declaration of a generic entity, when compared to a
C++ template declaration -- in the template "equivalent", the information
would have to be given in comments (and in that case, the compiler can't
guarantee its veracity), but is more likely going to be ignored by the writer
of the template.  In the C++ world, it's going to an extreme to document that
sort of thing.  For the "client" programmer to find out the hard way when they
try  to compile an instantiation of the template, is just considered business
as usual.  That's just one example, but the theme of making it easy for the
programmer to express design intent, not just operation, runs all the way
through the design of the language.

> It might
> be
> easier to use once you've mastered it, but it also is harder to learn.

OK, a couple of points...

1) I assume we're talking about C here, not C++.  I think C++ is a lot harder
to learn than Ada, because     while it's roughly the same in "size", it has a
lot of deep concepts (like "const correctness", linkage, etc.) that are not
only arcane, but are hightly cross-coupled, so that you kind of have to
understand all of it and keep your brain wrapped around it all in order to
really get any of it right.  For this reason, I don't think knowing C gives
one any real advantage when it comes to learning C++ vs. learning Ada.
Instead, what it gives you is a false sense that "I'm already halfway there",
which gives you the hope you need to keep trying to learn the screwy
language!  You're not really halfway there, but it helps to think you
are... :-)

2) While Ada is larger than C, you don't have to learn the whole language in
order to start using it., e.g. if you don't need tasking, you don't have to
learn Ada tasking, etc.

3) Since C is smaller, it's easier to master all the basic elements of the
language... but then so what?  What has it gotten you?  Now, in addition, you
also have to learn or invent ad hoc techniques, as in your example of structs
with callbacks.  And not only do you have to master the technique
intellectually, you then have to apply it correctly, and if you don't get it
right, the compiler can't tell you, because it has no clue what you are up
to.  You're going to have to debug it.

Debugging can be fun, but we usually have little control over the
circumstances that make it fun or un-fun.  And after you raise the level of
language abstraction so that you're detecting more bugs at compile-time, there
will still be plenty of honest run-time bugs left to go around, so you won't
miss the ones you don't have to debug anymore! :-)


> > Ada has
> > packages,
>
> C was ment to be used modular and for reuse : put your code in separate .c
> and .h files.
>
> > private types,
>
> C has that!
>
> > exceptions,
>
> you can program exceptions in C.  I never said that C has all these things,
> but you can program them, and there are masses of libraries available that
> have just what you need.
>
> > generics,
>
> use structs and callback functions and you have perfect generic types!
>
> > tasks,
>
> threads
>
> true enumeration types, true arrays,
> enumeration types in Ada are no different than they are in C.  Just because
> you have some fancy attributes (SUCC, PRED) doesn't mean that they are
> different or more powerful!  You can write functions that do exactly the
> same, even more, these functions have already been written numerous times
> and are available.
> With true arrays, do you mean out of bound checking, etc?  This can be done
> with _proper_ programming in C!

So, we have:

In Ada                                 In C
-----                                 ---

packages                              "header file / implementation file"
convention

private types                        ???

exceptions                            "you can program it",
setjmp()/longjmp(), whatever

generics                                structs & callbacks

tasks                                      threads


Yet, the Ada advocate claimed advantages for Ada because it has the things in
the first column.  What could be the explanation for this?  I see three
possibilities:

1) The Ada advocate is not aware of the things in the second column.  E.g., he
doesn't know that you can declare things in a shared header file, and then
supply the definitions of those things in a ".c" file.

2) The things in column 2 are equivalent to the things in column 1, or they
are just as good or better, e.g. threads give you everything that Ada tasks
do, and just as well, but the Ada advocate does not understand this.  For some
reason, he persists in his belief that the Ada version is better.  He just
doesn't get it.

3) The things in column 1 really are better than the things in column 2.


I think (1) can be safely dismissed.  You can probably assume, for example,
that Ada people know about #include.  Don't forget, a lot of Ada advocates are
C++ experts.  Believe me, those people understand #include.  Deeply.  In all
its glory.  Same with the example of tasking.  I don't think that when people
cite tasking as an advantage of Ada, they mean nothing more than "you can do
concurrent programming in Ada".

So it's gotta be either (2) or (3).

Let me take on the package thing, just as an example.

Let's say I have some C-style module, with the interface in "foo.h" and the
implementation in "foo.c".  OK, superficially, I have something analogous to
an Ada package spec and body.  But the thing is, "analogous" is as far as it
goes.  In important ways, they are not "equivalent"...

For instance... it's legal for foo.c to be incomplete.  It can even be empty.
How does foo.c "know" that it's supposed to be the "implementation" of foo.h?
It doesn't.  It can't.  Only the programmer knows.  C++ fixes this a little
bit, and in a not-very-satisfactory way, with its scopes (classes and
namespaces).  But then, if you are using C++ and you have a function
declaration in a .h file that is at the global scope, then there's another
problem, which is that thanks to overloading you can get the definition wrong
(doesn't match the prototype) and it's quite legal.  As far as C++ is
concerned, you didn't get it "wrong" (because only you know what "right"
is...), all you did was supply an additional, legal overloading at file scope
within the '.c' file.

For all these problems, you get to find out about it when you link the program
-- but only if there is an actual unresolved reference (think about the
implications of that for component development).  This is an irritation for
small, self-contained, one-person projects, but for large projects with
multiple teams, a product integration cycle, etc., it's more than an
irritation.

In C, everything is made to depend upon the linker.  This, along with textual
inclusion (independent compilation), is kind of the sine qua non of C/C++.  At
the linker level, which is primary in the C conception of modularity, the
fundamental unit is not the module, but the symbol.  The information loss
between what the compiler knows and what the linker can know is considerable.
(In combination with C++'s template design, this results in some truly
inscrutable link-time error messages!)

In Ada, the package spec is like a contract that the body has to fulfill, and
if it doesn't, it won't compile. How does the body of Foo know that it has
anything to do with the spec of Foo?  Simple, it says so right there: "package
body Foo is..."

That's not all...

When you put stuff in a .h file, you are making it available for other things
to #include.  And when they do that, they are dumping the stuff in your .h
file into their global scope, which is flat.  There's no way to say "The
Initialize() from foo.h" vs. "the Initialize() from bar.h" -- in fact, you
can't have both and include both.  The second one #included will result in a
redeclaration error.  So everyone has to use ad hoc naming conventions, like
"FooInitialize()".

So what's wrong with that, besides being hokey?  Well, does your concept of a
"module" really line up with the reality of a global scope that gets extended
when you #include the next thing?  Isn't the point of modularity supposed to
have something to do with encapsulation?  What place does "defensive
naming" have in any theory of modules?

Now, a C++ class defines a scope, so it gives you some namespace control.  But
a class is also a data type, so using one where all you want is namespace
control is awkward.  What was needed was a pure namespace that does not define
a data type.  This is why the C++ 'namespace' construct was invented.

But C++ namespaces are not that great.  For one thing, they are textually
disjoint.  Each file that declares namespace "foo" extends that namespace.
Namespaces partition the global namespace, but that's it.  They are not like
Ada packages.  There is no concept of separating interface and implementation,
yet enforcing the relationship at compile-time.  So while namespaces provide
one of the elements of a true module, they are not modules!  Also, neither
namespaces nor the .h/.c convention give you vsibility control (as in Ada's
private declarations).  Only classes give you something like this.

So C++ has three different mechanisms (header files, classes, and namespaces)
that overlap each other to some degree, and none of which gives you what you
should expect from a "module".  They only approximate it in different ways.

Not only that, but each #include of foo.h is subject to whatever #defines are
in effect at the point of the inclusion, which are not necessarily the same at
all the places where foo.h is #included.

Well, that's about all I have for now...

Respectfully,
Mark Lundquist






  parent reply	other threads:[~2000-01-21  0:00 UTC|newest]

Thread overview: 55+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2000-01-15  0:00 bitwise comparators Alexander Van Hecke
2000-01-15  0:00 ` David C. Hoos, Sr.
2000-01-16  0:00 ` Bryce Bardin
2000-01-16  0:00 ` Jeff Carter
2000-01-16  0:00 ` Matthew Heaney
2000-01-16  0:00 ` DuckE
2000-01-17  0:00   ` Alexander Van Hecke
2000-01-17  0:00     ` Mike Silva
2000-01-17  0:00       ` Brian Rogoff
2000-02-05  0:00         ` Ashley Deas Eachus
2000-02-05  0:00           ` Jeff Carter
2000-02-06  0:00           ` Andy
2000-02-07  0:00           ` Brian Rogoff
2000-02-09  0:00             ` Robert Iredell Eachus
2000-01-17  0:00       ` Alexander Van Hecke
2000-01-17  0:00         ` Gautier
2000-01-17  0:00         ` David Starner
2000-01-17  0:00         ` Mike Silva
2000-01-18  0:00           ` Charles Hixson
2000-01-17  0:00     ` tmoran
2000-01-17  0:00     ` Gautier
2000-01-18  0:00       ` Keith Thompson
2000-01-19  0:00         ` Ole-Hjalmar Kristensen
2000-01-17  0:00     ` Matthew Heaney
2000-01-17  0:00     ` David C. Hoos, Sr.
2000-01-17  0:00     ` Jeff Carter
2000-01-17  0:00       ` Alexander Van Hecke
2000-01-17  0:00         ` David Starner
2000-01-17  0:00           ` Alexander Van Hecke
2000-01-17  0:00             ` David Starner
2000-01-18  0:00             ` Preben Randhol
2000-01-18  0:00             ` Fraser
2000-01-18  0:00               ` Bertrand Augereau
2000-01-19  0:00                 ` Ted Dennison
2000-01-19  0:00                   ` Marin D. Condic
2000-01-19  0:00                     ` Ted Dennison
2000-01-18  0:00           ` Ted Dennison
2000-01-17  0:00         ` Gautier
2000-01-17  0:00           ` Alexander Van Hecke
2000-01-17  0:00             ` David Starner
2000-01-18  0:00             ` Gautier
2000-01-18  0:00           ` Ted Dennison
2000-01-18  0:00         ` Jeff Carter
2000-01-18  0:00           ` Keith Thompson
2000-01-19  0:00             ` Gisle S�lensminde
2000-01-19  0:00             ` Jeff Carter
2000-01-19  0:00               ` Keith Thompson
2000-01-19  0:00               ` David Starner
2000-01-19  0:00             ` Ole-Hjalmar Kristensen
2000-01-18  0:00         ` Pascal Obry
2000-01-21  0:00         ` Mark Lundquist [this message]
2000-01-21  0:00           ` Ada vs. C/C++ (was re: bitwise something-or-other) Mark Lundquist
2000-01-24  0:00           ` Hyman Rosen
2000-01-18  0:00     ` bitwise comparators Ted Dennison
2000-01-18  0:00     ` DuckE
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox