RRC
* Printer drivers
* UPS drivers
* USB device drivers (using libusb)
* Filesystem drivers (using fuse)
etc.
If you'll intend to write a Linux kernel driver (e.g. because you need to
manage device interrupts), you are bound to assembler and C -- unless you
are a C crack and write your own C++ kernel level interface.
Note there is no C or C++ standard lib in kernel level code! The kernel is
pure C/Assembler, things like "cout" or printf(), which are delegated to
the glibc in userland aren't available in kernelspace.
Kind regards
Jan
Thanks for your reply Jan.
Regards,
RRC
To RRC,
Note also that the kernel does not provide support for or even recognize all
those C++ facilities that are considered "features" over C. Polymorphism,
instantiation, operator overloads, inheritance, namespaces, and all those
other OO "good things" (sic) require a substantial amount of runtime support
that is just not available within the kernel
--
Lew Pitcher
Master Codewright & JOAT-in-training | Registered Linux User #112576
http://pitcher.digitalfreehold.ca/ | GPG public key available by request
---------- Slackware - Because I know what I'm doing. ------
Some things mainly require compile-time support, but RTTI and exceptions
require some runtime support. There was a project that ported the required
code to Linux to a surprising extent, try a websearch and see if that
project is still alive, and, if you find it, drop the link here, too.
cheers
Uli
Oh, come on; that's just nonsense. Templates and exceptions require
compiler and runtime cooperation, but polymorphism, instantiation, operator
overloads, inheritance, and namespaces don't require any runtime support at
all, and there is absolutely no reason why they cannot be used in a kernel
driver. No reason.
In fact, as long as you override a global "operator new" and "operator
delete" appropriately, you can even use the familiar new and delete for
memory allocation.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.
Interesting. Logically anythings possible! And if we were talking
about general embedded development, I'll agree that using C++ wouldn't
be too hard.
BUT if you look at developing a device driver (in Kernel mode), and
look at the facilities provided by the Linux kernel, I would have to
say that it can be done; but will take a long time and involve
rewriting a lot of stuff.
If someone really wants to use C++, I would suggest writing the Kernel
mode device driver bits in C/Assembler and then hooking in to it from
user land using C++.
Cheers
J
| Is it possible to write device drivers using C++ programming?
What aspect of C++ that is not a part of C ... and is not based on any
user space library, would you like to use? As far as I know, C99 and
GNU extensions to C provide quite reasonable facilities. But you do
need to remember that writing code inside the kernel is a while different
"ball game" than writing user space code, especially when that code is
involving any "critical sections".
The signifcant features of C++ are things more appropriate for user space
applications. Many programmers even go further than C++ and program in
languages like Java or Python in that arena. But the kernel needs to focus
on what is happening in a literal sense and avoid abstractions for the sake
of abstracting.
--
|---------------------------------------/----------------------------------|
| Phil Howard KA9WGN (ka9wgn.ham.org) / Do not send to the address below |
| first name lower case at ipal.net / spamtrap-200...@ipal.net |
|------------------------------------/-------------------------------------|
| Oh, come on; that's just nonsense. Templates and exceptions require
| compiler and runtime cooperation, but polymorphism, instantiation, operator
| overloads, inheritance, and namespaces don't require any runtime support at
| all, and there is absolutely no reason why they cannot be used in a kernel
| driver. No reason.
|
| In fact, as long as you override a global "operator new" and "operator
| delete" appropriately, you can even use the familiar new and delete for
| memory allocation.
If the kernel infrastructure were organized this way, I would believe you.
One reason that C++ is not an option is simply that the kernel is not made
for it. If you write a new kernel from scratch, C++ all the way, I would
guess it can work.
But you will find a lot of people whose skills you need for doing driver
writing won't write code for such a kernel. C++ is a more abstract kind
of language. People that work at lower levels on things like hardware
tend to also be people that work better without using abstractions. I
know I am one of them; abstractions hinder my programming, not help, in
most cases. It just depends on the application's ability to be represented
in an abstract way. A web site is easy to abstract. A piece of hardware
that I need to interface directly to bare metal with does cannot.
>On Wed, 05 Sep 2007 05:35:52 GMT Tim Roberts <ti...@probo.com> wrote:
>
>| Oh, come on; that's just nonsense. Templates and exceptions require
>| compiler and runtime cooperation, but polymorphism, instantiation, operator
>| overloads, inheritance, and namespaces don't require any runtime support at
>| all, and there is absolutely no reason why they cannot be used in a kernel
>| driver. No reason.
>|
>| In fact, as long as you override a global "operator new" and "operator
>| delete" appropriately, you can even use the familiar new and delete for
>| memory allocation.
>
>If the kernel infrastructure were organized this way, I would believe you.
>One reason that C++ is not an option is simply that the kernel is not made
>for it. If you write a new kernel from scratch, C++ all the way, I would
>guess it can work.
The question was not whether it is a good idea to write a Linux driver in
C++, or whether the Linux kernel makes it easy. The question was whether
it is possible. The answer to that question is YES, it is possible. A
driver can certainly be implemented as a C++ object. You need C adapter
plates to bridge between them, but that's easy.
>But you will find a lot of people whose skills you need for doing driver
>writing won't write code for such a kernel. C++ is a more abstract kind
>of language. People that work at lower levels on things like hardware
>tend to also be people that work better without using abstractions.
I write Windows drivers for a living (and Linux, although that's a much
smaller part). The Windows kernel is also a straight C environment, but
many people (including myself) have had great success writing Windows
drivers in C++. It just feels more natural to carry state as member
variables rather than globals.
>I know I am one of them; abstractions hinder my programming, not help, in
>most cases. It just depends on the application's ability to be represented
>in an abstract way. A web site is easy to abstract. A piece of hardware
>that I need to interface directly to bare metal with does cannot.
We will have to agree to disagree, I guess. Drivers have to deal with
requests, buffers, and queues, and it seems very natural to write
abstractions for those as C++ classes, where both the state and the
behavior get carried together.
It's all just syntactic sugar, of course, but if it make my driver easier
to understand, that's a measurable benefit.
> I write Windows drivers for a living (and Linux, although that's a
> much smaller part). The Windows kernel is also a straight C
> environment, but many people (including myself) have had great success
> writing Windows drivers in C++. It just feels more natural to carry
> state as member variables rather than globals.
> It's all just syntactic sugar, of course, but if it make my driver
> easier to understand, that's a measurable benefit.
Just to clarify: in C, one does not carry state as "globals" (at least not
any more than one would do so in C++) but rather in allocated structures
which are pretty much completely equivalent to a C++ class's member
variables.
Aside from that, I basically agree with Tim. It's just a different flavor
of syntactic sugar.
The bottom line for me is that the kernel gods in the linux world have
decreed that they will not put C++ drivers (or other C++ source code) into
the kernel. Of course, if you don't intend to put your source into the
mainstream kernel, you may not care about this.
GH
> Is it possible to write device drivers using C++ programming?
If you're willing to provide the neccesary infrastructure: Yes.
I've read a lot of awnsers on using C++ in the kernel here, some
are going into the right direction, but none got it right.
Let's get this straight: There's only very little runtime support
nedded for C++. Those are:
* calling constructors of globally declared, statically
instanciated class instances
* cast operators
* new and delete operators
All the other things can be perfectly done at compile time.
Polymorphism internally works much like e.g. the fops structure
used to implement inode syscalls.
In C++ each class instance carries a table (or a pointer to that
table) of function pointers to virtual functions. By inheriting
from a class, all the entries in these tables are inherited,
too, but those functions that are overridden replace those
entries in the derived table. Similairily you can create fops
structures that share a subset of syscalls, while descendants
differ.
If one got enough discipline he can do OOP perfectly with a
language like C. Just look at the GObject system. Or the Linux
kernel, which internally uses a lot of OOP concepts, only that
those things are done "manually" using structs and macros.
But if one would like to he could patch the GCC to do C++ stuff
using custom runtime functions, that are also linked into the
kernel. Then add some extra spice into the module init part (to
get static class instances properly initialized) and there you
are: C++ support for kernel programming.
In case you wonder why it's not done in Linux, simple reason:
Sometimes C++ can be a pain in the a*** if you have to get
something done very low level or to utilize a dirty trick. And
it makes dealing with binary objects a whole lot more
complicated, especially if you've to deal with different
compiler versions (there is no strict C++ ABI, yet).
Wolfgang Draxinger
--
E-Mail address works, Jabber: hexa...@jabber.org, ICQ: 134682867
> Note also that the kernel does not provide support for or even recognize all
> those C++ facilities that are considered "features" over C. Polymorphism,
> instantiation, operator overloads, inheritance, namespaces, and all those
> other OO "good things" (sic) require a substantial amount of runtime support
> that is just not available within the kernel
This is a myth that just won't die.
DS
> But you will find a lot of people whose skills you need for doing driver
> writing won't write code for such a kernel. C++ is a more abstract kind
> of language. People that work at lower levels on things like hardware
> tend to also be people that work better without using abstractions. I
> know I am one of them; abstractions hinder my programming, not help, in
> most cases. It just depends on the application's ability to be represented
> in an abstract way. A web site is easy to abstract. A piece of hardware
> that I need to interface directly to bare metal with does cannot.
This was precisely the same argument used to object to using C to
write drivers (rather than assembly) and it's wrong for precisely the
same reason. The idea that C++ hides things from you that are more
apparent in C is a myth. You can make things incomprehensible or clear
as day in either language with equal ease or difficulty.
DS
I beg to differ, exceptions and RTTI require some code.
> All the other things can be perfectly done at compile time.
> Polymorphism internally works much like e.g. the fops structure
> used to implement inode syscalls.
>
> In C++ each class instance carries a table (or a pointer to that
> table) of function pointers to virtual functions.
All classes that use virtual functions, that is. Others don't have this
pointer. Further, the table (the struct fops equivalent) is created on a
per-class base, not per instance. The instance only carries a pointer to
this table.
> By inheriting from a class, all the entries in these tables are inherited,
> too, but those functions that are overridden replace those
> entries in the derived table. Similairily you can create fops
> structures that share a subset of syscalls, while descendants
> differ.
>
> If one got enough discipline he can do OOP perfectly with a
> language like C. Just look at the GObject system. Or the Linux
> kernel, which internally uses a lot of OOP concepts, only that
> those things are done "manually" using structs and macros.
>
> But if one would like to he could patch the GCC to do C++ stuff
> using custom runtime functions, that are also linked into the
> kernel. Then add some extra spice into the module init part (to
> get static class instances properly initialized) and there you
> are: C++ support for kernel programming.
>
> In case you wonder why it's not done in Linux, simple reason:
> Sometimes C++ can be a pain in the a*** if you have to get
> something done very low level or to utilize a dirty trick.
I'd say that is a bad reason. Firstly, C integrates pretty well with C++, so
you can always use some C code, just like you can step to assembly today.
I'd much rather say that C++ is a very sharp tool, and most programmers
can't use it safely. In particular many C programmers, because they are not
aware of idioms common in C++, but that language lives of idioms and
conventions, otherwise it provides way too much rope to shoot yourself into
the foot.
> And it makes dealing with binary objects a whole lot more
> complicated, especially if you've to deal with different
> compiler versions (there is no strict C++ ABI, yet).
Well, binary objects are a pain in the ass either way, whether it's Linux
that changes its internal APIs or whether it's the C++ compiler matters
little. I'd say that this could be fixed with tools though, but nobody's
writing them. :/
regards
Uli
> I beg to differ, exceptions and RTTI require some code.
No, both can be done at compile time, though the implementation
may greatly differ from how it's done usually. Been there, done
that, programming µC with tight RAM constraints, but loads of
program ROM. However I've done that with pure C and a lot of
helper macros then.
For example exceptions can be done using a global backtrace table
instead of using a stack unwind approach (in multithreaded
environments you'd use thread local storage for those). RTTI can
be implemented in a similair way: Primitive types are dealt with
at compile time. Class instances carry a pointer (similair to a
vtbl) with them, that directs to a static classinfo structure.
All RTTI stuff can be done at compile time, but of course it's
easier to implement with a runtime.
> I'd say that is a bad reason. Firstly, C integrates pretty well
> with C++, so you can always use some C code, just like you can
> step to assembly today. I'd much rather say that C++ is a very
> sharp tool, and most programmers can't use it safely.
You can of course dive deep into the internals of C++ with the C
subset and assembler of course, but the resulting code will be
tied to a certain compiler or runtime implementation. And then
don't forget that you can't access identifiers by ther mangled
names from within C++ code, unless you make use of some probably
unavaliable #pragma.
Just have a look on how to access COM/ActiveX modules from pure
C, it's an utter mess. Microsoft developed those concepts with
only their own C++ compilers in mind and it took other compiler
vendors some iterations to adapt their's to the new "needs". The
problem is, that C++ doesn't define a strict ABI (yet), which in
the early days of C++ has lead to a lot of different ways how
polymorphism, RTTI, exception handling and the lot were
implemented (at compile time BTW). Today it's done the same way
by most compilers, though IMHO the way it's done is not really
the best one.
> Well, binary objects are a pain in the ass either way, whether
> it's Linux that changes its internal APIs or whether it's the
> C++ compiler matters little. I'd say that this could be fixed
> with tools though, but nobody's writing them. :/
They're not, as soon as you got a strict ABI. Any compiled
program is a bianary object of some sort, and somehow even the
oldest ELF binaries happyly run on even the newest *nix-boxes as
long at the accompanying libraries are installed - or you've got
it even purely static in an a.out.
And at least on a programming language level something like an
ABI should be the least problematic thing to tie down - I still
wonder why it hasn't been done for C++ in the first place. Maybe
because C never needed a pinned down ABI, as CPU architectures
implicitly brought something like an ABI with them and things
like exception handling or RTTI never were done on a language
level, but on a third party library/runtime level.
And one thing's for sure: My favor of C over C++ comes not from
an ignorance of C++, but from being fed up with it. I took my
first steps in the OOP programming world with C++, and nearly
all my programs for the next 10 years since then were written in
C++. But there more I worked with it, the more I figured it's
flaws, from a technical purist's point of view. I can't pin down
my feelings about it, but to me C++ is something like Lego
technic, while C feels like crafting a machine from bare
materials in a workshop - it may take longer, be harder, but
you've got far more possiblities to express your ideas, while
C++ gets you faster to a result. But this is a highly
subjective, even emotional view I got. Other people probably
differ, and it's good that way. Still I think C is one of the
fines programming languages in existance.
It is not the driver itself that should be an object. Instead, parts of
the hardware should be objects. The driver them implements the means to
access those objects. This is just abstracting hardware itself. It is
not a way to abstract how to implement such access to the hardware.
|>But you will find a lot of people whose skills you need for doing driver
|>writing won't write code for such a kernel. C++ is a more abstract kind
|>of language. People that work at lower levels on things like hardware
|>tend to also be people that work better without using abstractions.
|
| I write Windows drivers for a living (and Linux, although that's a much
| smaller part). The Windows kernel is also a straight C environment, but
| many people (including myself) have had great success writing Windows
| drivers in C++. It just feels more natural to carry state as member
| variables rather than globals.
But C++ is not necessary to achieve such an organization. I've been doing
things that way for a couple decades in C and assembly.
|>I know I am one of them; abstractions hinder my programming, not help, in
|>most cases. It just depends on the application's ability to be represented
|>in an abstract way. A web site is easy to abstract. A piece of hardware
|>that I need to interface directly to bare metal with does cannot.
|
| We will have to agree to disagree, I guess. Drivers have to deal with
| requests, buffers, and queues, and it seems very natural to write
| abstractions for those as C++ classes, where both the state and the
| behavior get carried together.
Yeah, we will disagree on some things. Maybe we will agree on more than you
might guess. Object oriented as a design means is a very good way to do it.
But I don't agree with the choice of C++ for it.
| It's all just syntactic sugar, of course, but if it make my driver easier
| to understand, that's a measurable benefit.
The design is more than syntactic sugar. The choice of language may be
that (aside from the implementations it carries around).
| All the other things can be perfectly done at compile time.
| Polymorphism internally works much like e.g. the fops structure
| used to implement inode syscalls.
Then it should be possible to make a hybrid language that has these
parts of C++ language synatx while not adding anything at all to the
C library (if said library is even being used).
| In C++ each class instance carries a table (or a pointer to that
| table) of function pointers to virtual functions. By inheriting
| from a class, all the entries in these tables are inherited,
| too, but those functions that are overridden replace those
| entries in the derived table. Similairily you can create fops
| structures that share a subset of syscalls, while descendants
| differ.
And this can be entirely done in compiled code without bloat?
If so, great. Then let's make the hybrid language and keep it lean.
| If one got enough discipline he can do OOP perfectly with a
| language like C. Just look at the GObject system. Or the Linux
| kernel, which internally uses a lot of OOP concepts, only that
| those things are done "manually" using structs and macros.
I have done OOD in C. I say OOD instead of OOP because the way I do it
is to make the design itself OO, but implement it without OOP formality.
| But if one would like to he could patch the GCC to do C++ stuff
| using custom runtime functions, that are also linked into the
| kernel. Then add some extra spice into the module init part (to
| get static class instances properly initialized) and there you
| are: C++ support for kernel programming.
|
| In case you wonder why it's not done in Linux, simple reason:
| Sometimes C++ can be a pain in the a*** if you have to get
| something done very low level or to utilize a dirty trick. And
| it makes dealing with binary objects a whole lot more
| complicated, especially if you've to deal with different
| compiler versions (there is no strict C++ ABI, yet).
The hybrid language shouldn't need any more ABI than C itself already has.
> On Sat, 08 Sep 2007 01:20:16 +0200 Wolfgang Draxinger
> <wdrax...@darkstargames.de> wrote:
>| All the other things can be perfectly done at compile time.
>| Polymorphism internally works much like e.g. the fops structure
>| used to implement inode syscalls.
>
> Then it should be possible to make a hybrid language that has these
> parts of C++ language synatx while not adding anything at all to the
> C library (if said library is even being used).
That language existed up until the mid 1990's. It was called C++.
--
-| Bob Hauck
-| "Reality has a well-known liberal bias." -- Stephen Colbert
-| http://www.haucks.org/
It would be nonsensical to use 'this precise argument' wrt to C,
because the criticized facilities do not exist in C.
> The idea that C++ hides things from you that are more
> apparent in C is a myth.
C++ has support for automatically invoking subroutines in various
cases (constructors, destructors and overloaded operators), which
means that just looking at a piece of code is not sufficient to
determine what will actually happen at runtime when this code is
executed. It is additionally necessary to know the implementations of
any classes which may be used in it. In contrast to this, every
subroutine invocation in C is explicit.
NB: I am not arguing in favor or against any of both. I stopped using
C++ because I got tired of g++ then constantly occuring ABI changes
and the most 'harsh' statement I would make regarding the language is
that I have never really missed it.
It's not just syntactic sugar. I guess the case you mean is this:
// C++
some_type t;
t.do_something();
// C
struct some_type t;
do_something(&t);
However, it's not that easy. Firstly, the second snippet must be written
like this:
// C
struct some_type t;
create(&t);
do_something(&t);
destroy(&t);
...because we also need calls to constructor and destructor here. But that
still is not enough, we need this:
// C
struct some_type t;
some_type_create(&t);
some_type_do_something(&t);
some_type_destroy(&t);
...because we don't have overloading in C (static functions help a bit).
However, that is still a bit away from what we get in C++, let's see:
// C
int e;
struct some_type t;
e = some_type_create(&t);
if(e)
return e;
e = some_type_do_something(&t);
some_type_destroy(&t);
return e;
...because in C++ failures of constructors are signalled using exceptions
and we need an equivalent form of error management, too. Now we are closer
to the C++ code.
However, try extending the C++ code with other created objects and function
calls, e.g. like this:
// C++
some_type t;
t.do_something();
other_type o;
o.do_something();
something_else( o, t);
...which just adds another object and another memberfunction call and
finally a call to a function that receives both objects as parameter. I
wouldn't say this is a really uncommon situation, in fact (kernel) reality
can easily become much more complex. Then, try writing the equivalent C
code. That code will be swamped with cleanup code and error handling code
and will never achieve the simplicity and expressiveness that C++ code can
achieve. Yes, a good C coder can still structure the code so that it
remains readable and maintainable, but not in the same amount of code.
Further, it might perform slower than the C++ equivalent because that one
doesn't need the error handling normally and provide less functionality
because exceptions can carry much more information than just a simple
integer errorcode, so we are still comparing apples with oranges!
Also, there are still some things that C++ offers that I haven't even
touched on yet, like e.g. namespaces. If 'other_type' above was
rather 'some_module::other_type', how about the call to 'something_else'?
In C++ you get ADL, so the function doesn't have to be prefixed
with 'some_module::' even! Other things are overloadable operators, which
sometimes allow a very intuitive syntax for some things (no, streams are
not a good example for that, strings are though). Or how about
transparently wrapping a type with a class in order to change its
behaviour? The whole hack in GCC with __iomem in order to produce warnings
could easily be avoided.
No, seriously, 'syntactic sugar' is way too harmless a name for all those
differences. C++ can be used to move code to a whole new level of
abstraction, and that abstraction would be very useful even in kernel
programming.
Uli
> > The idea that C++ hides things from you that are more
> > apparent in C is a myth.
> C++ has support for automatically invoking subroutines in various
> cases (constructors, destructors and overloaded operators), which
> means that just looking at a piece of code is not sufficient to
> determine what will actually happen at runtime when this code is
> executed.
So does C. For example, invoking a function through a function pointer
makes it unclear by looking at the code what will happen at runtime.
> It is additionally necessary to know the implementations of
> any classes which may be used in it. In contrast to this, every
> subroutine invocation in C is explicit.
That's complete and total bullshit, and I suspect that you know it. I
picked this chunk of code from the first file in the Linux kernel I
happened to stumble on.
if (inode->i_op && inode->i_op->setattr) {
error = security_inode_setattr(dentry, attr);
if (!error)
error = inode->i_op->setattr(dentry, attr);
} else {
Please tell me how I find out what that line that starts "error = "
does and how many subroutines it invokes.
> NB: I am not arguing in favor or against any of both. I stopped using
> C++ because I got tired of g++ then constantly occuring ABI changes
> and the most 'harsh' statement I would make regarding the language is
> that I have never really missed it.
I'm not arguing in favor or against either language either. I'm just
saying that the typical arguments used against C++ are total nonsense.
You can write unclear code as easily in C as you can in C++, and you
can write clear code as easily in either. This particular issue is in
fact a significant advantage for C++, because it standardizes how you
write this type of code when you want to write this type of code.
The disadvantages of C++ lie elsewhere.
DS
You are trying to sidestep the issue by writing about something
entirely different from my text above. C++ supports automatic
subroutine invocation as result of statements that are not technically
function calls. C doesn't.
Yep, and that's a good thing, because it allows you to shift your attention
to a different level of abstraction. However, I'm not going to argue the
merits of this. Still, what strikes me most was your assertion following
the above quote:
> It is additionally necessary to know the implementations of
> any classes which may be used in it.
By the same logic, that would mean that you also have to know the
implementation of any plain function involved somewhere. No, you are still
coding against an interface - when the implementation starts mattering to
you, the interface is typically badly implemented and documented,
regardless of the language used for it.
> In contrast to this, every subroutine invocation in C is explicit.
Every subroutine invokation has to be coded manually, you can't delegate it
because there is nothing you can hook into, like the mentioned function
calls following the scope of an object. Writing the same cleanup code
produces LOC but doesn't add anything to the final executable. Anyway, all
you have to do in order to get to the subroutine calls is to be aware of
things, like you seem to be. You only have to know that creating an object
or destroying it involves code that is executed, even though there is
nothing explicitly calling a function. Nothing new compared to C
initialisations, just that the possibilities have been enlarged.
Uli
> You are trying to sidestep the issue by writing about something
> entirely different from my text above. C++ supports automatic
> subroutine invocation as result of statements that are not technically
> function calls. C doesn't.
And supporting something is bad because that means you *have* to use
it, even when it does more harm than good. No, wait, it doesn't.
DS
In the original context of this thread (which you - as usually -
considered to be 'more useful if removed') your statement doesn't make
any sense. The original claim was (paraphrase) that 'C++ does not hide
things from the programmer'. This claim is wrong, because C++ does
hide subroutine invocations in variable declarations, block exits and
'plainly looking' application of operators to variables.
I haven't written anything regarding an opinion I could have that
this would be 'good' or 'bad', for the precise reason that I simply
don't have any. Program languages are tools and not fetishes,
consequently, one uses what is there and (occasionally) complains
about what is lacking. Among the more popular languages, C is distinct
because it doesn't follow the usual paradigm of 'try to encompass all
parts of "the world" the language designer currently can imagine' but
rather 'try to provide what is minimally necessary for the language to
be useful'. This comes with the advantage that one is not forced to
bend less-than-perfectly fitting abstractions to tasks they were never
intended to solve and the obvious disadvantage that there are none.
It could be called another attempt at side-stepping the actual
problem. But the language is quite usable nevertheless.
That's 'a thing' and it means something is different :-).
> However, I'm not going to argue the
> merits of this. Still, what strikes me most was your assertion following
> the above quote:
>
>> It is additionally necessary to know the implementations of
>> any classes which may be used in it.
>
> By the same logic, that would mean that you also have to know the
> implementation of any plain function involved somewhere.
The difference is that it is not necessary to know anything about the
implementation of the subroutine to see that it is invoked, while it
is on the other hand necessary to know something about the
implementation of a set of classes to know if a + or a variable
declaration will lead to a subroutine invocation.
The question why one would want to know that in the first place would
be a different one.
[...]
>> In contrast to this, every subroutine invocation in C is explicit.
>
> Every subroutine invokation has to be coded manually, you can't delegate it
> because there is nothing you can hook into, like the mentioned function
> calls following the scope of an object. Writing the same cleanup code
> produces LOC but doesn't add anything to the final executable.
Without using classes whose constructors allocate ressources in need
of cleanup, 'cleanup code' can often be avoided (eg by allocating
temporary buffers of any kind on the stack, which constructors cannot
sensibly do).
> be prefixed with 'some_module::' even! Other things are overloadable
> operators, which sometimes allow a very intuitive syntax for some
> things (no, streams are not a good example for that, strings are
> though).
Operator overloading -- particularly for string handling -- is one of the
evils often mentioned with respect to doing C++ development in the
kernel. Have you ever considered the under-the-covers memory management
that occurs with something as simple as this:
string s1, s2, s3;
...
s1 += s2 + "," + s3;
That may be fine for application code where the coder (presumably) knows
when and how often it's going to be executed and can judge the tradeoffs.
But it's almost certainly a bad idea within the kernel.
> No, seriously, 'syntactic sugar' is way too harmless a name for all
> those differences. C++ can be used to move code to a whole new level
> of abstraction, and that abstraction would be very useful even in
> kernel programming.
I would say that, while essentially correct, 'syntactic sugar' is too
harmless _sounding_. That "whole new level" of abstraction can also be
dangerous; kernel programming is exacting and virtually all of it is
performance-critical for someone. There are many features in C++ that
make it easy to forget what's really going on under-the-covers.
In my view, it boils down to this:
It's not impossible to write OS code with C++; it's not even impossible
to write _good_ OS code with C++. However, it's way too _easy_ for C++
programmers to throw in the sorts of things that make OS code suck.
GH
Ah, I see now. Rainer, we have a small misunderstanding. When people talk
about the implementation of something, they typically mean everything
_behind_ the interface. Whether a class has overloaded operators is part of
the interface (not the implementation!) of that class, just like the
function parameters are part of the interface of a normal function. And of
course, when using objects of a class, you should be aware of the
interface. OTOH when doing OOP using C, you have the same requirements,
only that every call uses normal function syntax.
> The question why one would want to know that in the first place would
> be a different one.
It seemed to me that you were implying that this was something that makes
C++ unsuitable for kernel programming, but the rationale you seemed to give
was faulty. I now see that we were just misunderstanding each other.
>>> In contrast to this, every subroutine invocation in C is explicit.
>>
>> Every subroutine invokation has to be coded manually, you can't delegate
>> it because there is nothing you can hook into, like the mentioned
>> function calls following the scope of an object. Writing the same cleanup
>> code produces LOC but doesn't add anything to the final executable.
>
> Without using classes whose constructors allocate ressources in need
> of cleanup, 'cleanup code' can often be avoided (eg by allocating
> temporary buffers of any kind on the stack, which constructors cannot
> sensibly do).
Huh? Of course they can, or I'm misunderstanding you again. Can you give an
example, e.g. a piece of C code that can't be converted.
Uli
Well, it's a choice you make. If you have some tight inner loops, you can
use str*() functions on a once-allocated buffer. OTOH, you can use a simple
string class where timing doesn't matter too much and get code that is not
prone to buffer overruns and resource-management related bugs almost for
free.
> In my view, it boils down to this:
> It's not impossible to write OS code with C++; it's not even impossible
> to write _good_ OS code with C++. However, it's way too _easy_ for C++
> programmers to throw in the sorts of things that make OS code suck.
Sadly, there is some truth in this. C++ is a too sharp tool for most people,
and it gives you much more rope to shoot yourself in the foot than C.
However, even C has way too much rope for many people, and bad C code
exists even in Linux, and people can learn.
Uli
> | In C++ each class instance carries a table (or a pointer to that
> | table) of function pointers to virtual functions. By inheriting
> | from a class, all the entries in these tables are inherited,
> | too, but those functions that are overridden replace those
> | entries in the derived table. Similairily you can create fops
> | structures that share a subset of syscalls, while descendants
> | differ.
>
> And this can be entirely done in compiled code without bloat?
Of course it can be done entirely in compiled code. As for bloat,
whenever you have to perform extra operations, as you do for
implementing virtual function, there will be code that must be
generated. Whether you would call that "bloat" or not is an interesting
question, especially when you consider that you may end up having to
implement similar constructs in hand-written code.
> If so, great. Then let's make the hybrid language and keep it lean.
Raw C++ -- that is C++ code that does not use the standard libraries --
is already remarkably lean, sometimes even more so that C, especially if
you take into account the fact that it offers facilities, like virtual
functions, that can obviate the need to write a lot of boilerplate code
and that is always a good thing.
> The hybrid language shouldn't need any more ABI than C itself already has.
It would need some additional stuff -- no getting around that --
especially in regards to layout of object v-tables.
-n
> In the original context of this thread (which you - as usually -
> considered to be 'more useful if removed') your statement doesn't make
> any sense. The original claim was (paraphrase) that 'C++ does not hide
> things from the programmer'. This claim is wrong, because C++ does
> hide subroutine invocations in variable declarations, block exits and
> 'plainly looking' application of operators to variables.
Only if you *choose* to hide these things. C++ doesn't hide anything,
the programmer may choose to hide things if he wishes.
I can trivially write C code where you can't tell when and where
functions are being invoked if I want to. In fact, almost all of these
claimed disadvantages can be created in C with suitable #define's and
run-time code.
For example:
if(complex_macro_magic_you_cant_figure_out) invoke_function();
Does this invoke a function or doesn't it? It might. That's all you
can say.
>> And supporting something is bad because that means you *have* to use
>> it, even when it does more harm than good. No, wait, it doesn't.
This is the point -- you don't blame the language for a feature you
don't like, you blame whoever chose to use that feature in a case
where it did more harm than good.
All of these features can be opted out of. None of them are forced on
you. Choices are never bad.
DS
Rainer> C++ has support for automatically invoking subroutines in
Rainer> various cases (constructors, destructors and overloaded
Rainer> operators),
Besides this, C++ also generates code autotragically(TM): default
constructors, copy constructors, assignment operators. These, when
combined with the autotragic subroutine invocation, can create
"mysterious" effects that many programmers cannot understand or debug.
Rainer> which means that just looking at a piece of code is not
Rainer> sufficient to determine what will actually happen at
Rainer> runtime when this code is executed.
I've seen a guy looking at his code for a day without knowing why
there is a bug in his code. He even suspected that the compiler was
wrong. I had a look at his code, and immediately found the reason:
autotragically generated copy constructor being invoked autotragically
when an argument is passed-by-value to a function.
Syntactically, that's just one function invocation. So, that poor guy
couldn't imagine that are other functions being called. And it's even
harder for him to realize that the C++ compiler can autotragically
generate copy constructors.
Rainer> It is additionally necessary to know the implementations
Rainer> of any classes which may be used in it. In contrast to
Rainer> this, every subroutine invocation in C is explicit.
Yeah. I like C's simplicity. :)
(Don't take me work. I also write programs in C++ and Java. I use
whatever language/tool I find appropriate for a given task. For
kernel code? I find C more appropriate than C++. I'm the kind of
person who would learn a more appropriate tool rather than trying hard
to use my familiar but inappropriate tool to handle new tasks.)
Rainer> NB: I am not arguing in favor or against any of both. I
Rainer> stopped using C++ because I got tired of g++ then
Rainer> constantly occuring ABI changes and the most 'harsh'
Rainer> statement I would make regarding the language is that I
Rainer> have never really missed it.
But that's a "feature" of C++. The ABIs are deliberately incompatible
between different compilers (or different compiler versions), so that
they won't be mistakenly calling one another. They shouldn't be
calling one another, because they use very different implementations
of the complicated features of C++.
--
Lee Sau Dan 李守敦 ~{@nJX6X~}
E-mail: dan...@informatik.uni-freiburg.de
Home page: http://www.informatik.uni-freiburg.de/~danlee
Wolfgang> Ulrich Eckhardt wrote:
>> I beg to differ, exceptions and RTTI require some code.
Wolfgang> No, both can be done at compile time,
Really? Do you know what the "R" in "RTTI" stand for?
[...]
>>> By the same logic, that would mean that you also have to know the
>>> implementation of any plain function involved somewhere.
>>
>> The difference is that it is not necessary to know anything about the
>> implementation of the subroutine to see that it is invoked, while it
>> is on the other hand necessary to know something about the
>> implementation of a set of classes to know if a + or a variable
>> declaration will lead to a subroutine invocation.
>
> Ah, I see now. Rainer, we have a small misunderstanding. When people talk
> about the implementation of something, they typically mean everything
> _behind_ the interface. Whether a class has overloaded operators is part of
> the interface (not the implementation!) of that class, just like the
> function parameters are part of the interface of a normal function.
This occurred to me yesterday as well. I would refer to both
destructors and default constructors as parts of the
implementation. They are (usually) never called directly and exist
only because the class needs them for some internal-only purposes. I
am somewhat uncertain about overloaded operators because the use of
the corresponding symbols is not specific to classes which eventually
overload them.
> And of course, when using objects of a class, you should be aware of
> the interface. OTOH when doing OOP using C, you have the same
> requirements, only that every call uses normal function syntax.
That's the difference: To know that
A a;
causes a subroutine to be called (and is consequently likely a
non-trivial action), a reader needs to be aware of the definition of
the class A and of the definitions of all of its eventual members
having a class-type and their members and so on.
A a;
init_an_a(&a);
makes this explicit.
[...]
>> Without using classes whose constructors allocate ressources in need
>> of cleanup, 'cleanup code' can often be avoided (eg by allocating
>> temporary buffers of any kind on the stack, which constructors cannot
>> sensibly do).
>
> Huh? Of course they can, or I'm misunderstanding you again. Can you give an
> example, e.g. a piece of C code that can't be converted.
Memory allocated by a constructor for use by the class until
destruction cannot be stack-allocated, because it would need
to be allocated in the strack frame of some caller having a suitable
lifetime.
'The programmer' may chose to use Simula-67 instead, and immediatly,
the resulting code will be free of any C++-features. But since the
programmer is free to pick S/360 assembler at any time, there is not
more of of point in claiming that Simula-67 has any features than in
claiming that C++ had. Moreover, since the programmer is human and
humans always die, there is actually no point in claiming that
anything has features, because after death, they cannot be used
anymore and whoever claims to be still alive is just a transient
measurement error.
> I can trivially write C code where you can't tell when and where
> functions are being invoked if I want to. In fact, almost all of these
> claimed disadvantages can be created in C with suitable #define's and
> run-time code.
>
> For example:
> if(complex_macro_magic_you_cant_figure_out) invoke_function();
>
> Does this invoke a function or doesn't it? It might. That's all you
> can say.
Consequently, people who consider this C++ feature a disadvantage
should consider using the preprocessor to piggy-back a somewhat
differen language than C on top of C, too.
BTW, did you know that C does not differ from Algol?
> Rainer> C++ has support for automatically invoking subroutines in
> Rainer> various cases (constructors, destructors and overloaded
> Rainer> operators),
>
> Besides this, C++ also generates code autotragically(TM): default
> constructors, copy constructors, assignment operators. These, when
> combined with the autotragic subroutine invocation, can create
> "mysterious" effects that many programmers cannot understand or debug.
Your trademarked quip and quirky use of language notwithstanding, it's
really not that mysterious at all.
> Rainer> which means that just looking at a piece of code is not
> Rainer> sufficient to determine what will actually happen at
> Rainer> runtime when this code is executed.
>
> I've seen a guy looking at his code for a day without knowing why
> there is a bug in his code. He even suspected that the compiler was
> wrong. I had a look at his code, and immediately found the reason:
> autotragically generated copy constructor being invoked autotragically
> when an argument is passed-by-value to a function.
Engage sarcasm mode: "That's clearly the fault of the language, yes.
After all, it's not like the programmer asked to pass a non-POD argument
by value!"
> Syntactically, that's just one function invocation. So, that poor guy
> couldn't imagine that are other functions being called. And it's even
> harder for him to realize that the C++ compiler can autotragically
> generate copy constructors.
The simple fact is that people who don't know how the tool they're
using works will end up with a hole in their foot -- whether their tool
of choice is a nail gun, C or C++. And it won't be the tool's fault.
-n
> The simple fact is that people who don't know how the tool
> they're using works will end up with a hole in their foot
And the more complex the tool is, the more likely that is to
happen.
> -- whether their tool of choice is a nail gun, C or C++. And
> it won't be the tool's fault.
Right. It's the tool designer's fault. Tools have to be used
by humans. Somebody who designs a tool that is so complex that
nobody can understand how to properly use it has done a bad job
designing that tool -- unless the ojbective was to waste time
and create confusion and disfunction. Stroustrup has been
accused (in a slightly tounge-in-cheek way) of having that
objective when he designed of C++.
http://artlung.com/smorgasborg/Invention_of_Cplusplus.shtml
--
Grant Edwards grante Yow! Alright, you!!
at Imitate a WOUNDED SEAL
visi.com pleading for a PARKING
SPACE!!
[...]
> Rainer> NB: I am not arguing in favor or against any of both. I
> Rainer> stopped using C++ because I got tired of g++ then
> Rainer> constantly occuring ABI changes and the most 'harsh'
> Rainer> statement I would make regarding the language is that I
> Rainer> have never really missed it.
>
> But that's a "feature" of C++. The ABIs are deliberately incompatible
> between different compilers (or different compiler versions), so that
> they won't be mistakenly calling one another.
The meaning of ABI is 'application binary interface', for instance,
function call and return sequences, which registers (if any) are
supposed to be used for passing arguments, which the callee is
supposed to preserve, which the caller is supposed to preserve and so
on. What you are likely referring to is 'name mangling' and that's
actually used to encode the signature of a subroutine being overloaded
at the C++ level into it a linker visible name, which means one gets
'overload resolution' for free as part of the linking process. What I
was referring to that there was a time when each new g++-release would
produce binaries which could not be linked to binaries produced by
older g++-releases (at least according to documentation), meaning, if
one wants to use a 'newer' compiler for some part of something, all
external C++ libraries need to be recompiled with the newer compiler
first.
Combined with the related nuisance that the language accepted by the
compiler is likely to change with a new release, too, this means
instead of developing new code, one will likely need to spend some time
testing and fixing occurence of ISO-non-conformance which happened to
be translated to something sensible by the older compiler in old code.
Except randomly dropping useful extensions and the single Aergernis
that gcc nowadays (reportedly) pretends that the set of representable
signed integers on a CPU is inifinte, despite the fact that it isn't,
the C-compiler has been more stable in this respect. Imagine sitting
on x*10^4 LOC of inerited C-code written by a set of random people in
random states of cluelessness about what would be standard-conformant,
which "works" and no time to do anything with this code except fixing
really serious bugs in it ...
>>>>>> "Wolfgang" == Wolfgang Draxinger
>>>>>> <wdrax...@darkstargames.de> writes:
>
> Wolfgang> Ulrich Eckhardt wrote:
> >> I beg to differ, exceptions and RTTI require some code.
>
> Wolfgang> No, both can be done at compile time,
>
> Really? Do you know what the "R" in "RTTI" stand for?
Runtime.
However this is just a silly argument. Here's a sort of RTTI in
plain C (and the RTTI of C++ is not very different to it):
struct structinfo {
int id;
char *structname;
};
struct A {
struct structinfo *__si;
// stuff;
};
struct B {
struct structinfo *__si;
// stuff;
};
enum __si_id = { struct_a, struct_b };
struct structinfo __si_table[] = {
{ struct_a, "struct a" },
{ struct_b, "struct b" },
};
struct A* new_a()
{
struct *_my_A = malloc( sizeof(struct A) );
memset(_my_A, 0, sizeof(struct A) );
_my_A.__si = __si_table[struct_a];
return _my_A;
}
struct B* new_b()
{
struct *_my_B = malloc( sizeof(struct B) );
memset(_my_B, 0, sizeof(struct B) );
_my_B.__si = __si_table[struct_b];
return _my_B;
}
void print_structinfo(struct structinfo const * const si)
{
puts(si.structname);
}
void foobar()
{
struct A* a = new_a();
struct B* b = new_b();
print_structinfo( (struct structinfo const * const) A );
print_structinfo( (struct structinfo const * const) B );
}
Here you go: Compile time RTTI. Make sure, that each struct has a
pointer to a structinfo at offest 0 (or any other offset, as
long it's the same among all structs).
RTTI of C++ is done in exactly the same way: Every class instance
carries a pointer to a table entry that has information about
the class. The Runtime of RTTI means, that you can determine the
type of a variable, you don't know the exact type of (e.g. a
base class pointer) at program runtime, e.g. in a callback
function. But it doesn't require any additional runtime support,
it can be compiled completely self contained.
> Right. It's the tool designer's fault. Tools have to be used
> by humans. Somebody who designs a tool that is so complex that
> nobody can understand how to properly use it has done a bad job
> designing that tool -- unless the ojbective was to waste time
> and create confusion and disfunction. Stroustrup has been
> accused (in a slightly tounge-in-cheek way) of having that
> objective when he designed of C++.
Your analogy fails dismally. Yes, someone who has designed a tool that
is so complex that nobody can understand how to use it *to* *do* *a*
*particular* *task* has done a bad job designing that tool. But a tool
that has features that nobody can understand is no worse than a tool
that doesn't have those features. You can simply opt not to use those
features.
The objection to C++ comes down to "C++ has features I don't like".
Since you don't have to use any feature you don't like, this reduces
to "people write code in C++ that I can't understand". Well, they can
write obfuscated code in *any* useful language.
What you are essentially arguing is that *I* shouldn't use a feature
*you* don't understand because that way, you'll be more easily able to
understand my code. My response would be that additional features
never compel a person to write more complex code but they sometimes
enable people to write simpler code. If it's *my* code, I'm the one
that decides what priority to place on complexity versus simplicity,
and I will not let you object to my having more choices.
DS
It's not an analogy.
> Yes, someone who has designed a tool that is so complex that
> nobody can understand how to use it *to* *do* *a* *particular*
> *task* has done a bad job designing that tool. But a tool that
> has features that nobody can understand is no worse than a
> tool that doesn't have those features.
Yes it is.
> You can simply opt not to use those features.
No you can't. People are very bad at recognizing when they
don't understand something or are bad at something. That's a
proven fact of human psychology and there's not much you can do
about it:
http://en.wikipedia.org/wiki/Dunning-Kruger_effect
http://www.apa.org/journals/features/psp7761121.pdf
They _think_ they understand the features so they use them.
However, they don't really understand the features so the code
they write is broken. Even if they're given complex but
correct code to maintain, they'll think they understand it
better than the author and break it. I've seen it happen over
and over again.
> What you are essentially arguing is that *I* shouldn't use a
> feature *you* don't understand
No, that's not at all what I'm arguing. I'm arguing that the
features are too complex so they end up being mis-understood
and used to write broken code.
However, even though that wasn't my point, arguing that you
should write code that's easy for others to understand is still
a valid argument. Even if your code starts out correct, if
it's too complex for other people to understand, it will end up
broken just the same as if it were written by somebody who
didn't understand the language features to start with.
Writing code that's easy to read and understand is arguably
more important than writing correct code. Correct but complex
code decays into brokenness. Easy to read code imporoves.
--
Grant Edwards grante Yow! The FALAFEL SANDWICH
at lands on my HEAD and I
visi.com become a VEGETARIAN ...
Why? It sounds like you are saying that user-mode coders are smart enough
to worry about the memory implications of a statement like that, but kernel
coders are not.
You are correct in saying that it is easy to write C++ statements that do
more than they seem to, but when I write constructs like that for the first
time, I usually generate the assembly so that I know what's going on. Since
that compiler doesn't know the difference between user and kernel mode,
that knowledge helps in either environments.
--
Tim Roberts, ti...@probo.com
Providenza & Boekelheide, Inc.
> No, that's not at all what I'm arguing. I'm arguing that the
> features are too complex so they end up being mis-understood
> and used to write broken code.
I utterly and totally reject this argument. The presumption is that
you understand these features better than everybody else, and I just
don't believe that. In any event, even if it were true, even if nobody
else on the planet but me understood these features well enough to
know when to use them safely, *I'd* still rather have the choice to
use them where I think they're beneficial.
This is Linux guys. You're supposed to be allowed to shoot yourself in
the foot if you *want* to. There isn't supposed to be somebody else
saying, "this tool is so dangers that you shouldn't have the choice to
use it".
> However, even though that wasn't my point, arguing that you
> should write code that's easy for others to understand is still
> a valid argument. Even if your code starts out correct, if
> it's too complex for other people to understand, it will end up
> broken just the same as if it were written by somebody who
> didn't understand the language features to start with.
Absolutely. And if that's the top priority, you can opt to use these
features when, and only when, they improve this. However, other people
may, for valid reasons, find other things to be more important in some
cases. You are arguing that them having this choice is wrong.
> Writing code that's easy to read and understand is arguably
> more important than writing correct code. Correct but complex
> code decays into brokenness. Easy to read code imporoves.
No option can make code harder to understand. I reject your argument
that nobody but you is smart enough to know when to use these
features.
DS
Yes, C forces you to make explicit calls so that an object may establist its
class invariants.
> I am somewhat uncertain about overloaded operators because the use
> of the corresponding symbols is not specific to classes which
> eventually overload them.
Well, overloaded operators are pretty easy to spot, aren't they? I mean you
only have so many fundamental types (for which there are already operator
overloads in C) where you know that an operator is builtin. Everything else
must be user-overloaded. If that causes a problem, i.e. doesn't do what one
could guess from the context, then something else is wrong: it's the
principle of least surprise that was violated, i.e. someone wrongly chose
to overload something who's name doesn't quite describe it.
>> And of course, when using objects of a class, you should be aware of
>> the interface. OTOH when doing OOP using C, you have the same
>> requirements, only that every call uses normal function syntax.
>
> That's the difference: To know that
>
> A a;
>
> causes a subroutine to be called (and is consequently likely a
> non-trivial action), a reader needs to be aware of the definition of
> the class A and of the definitions of all of its eventual members
> having a class-type and their members and so on.
>
> A a;
>
> init_an_a(&a);
>
> makes this explicit.
Yeah, and you forgot the error checking and cleanup (in every damn path).
Anyway, I don't call this a disadvantage. Whatever invariants type A needs,
those are already established by the constructor and protected so that only
temporarily during a call to a memberfunction they are invalidated. After
the object isn't needed anymore, cleanup is performed automatically. All of
this is capsuled in a nice modular way, so you can't possibly (barring
vandalism) forget to do it. In a kernel, where correct resource management
is fundamental, this sounds like a good idea.
> Memory allocated by a constructor for use by the class until
> destruction cannot be stack-allocated, because it would need
> to be allocated in the strack frame of some caller having a suitable
> lifetime.
Well, then you put it as member into the class itself - that was easy. Just
to help you, the only thing where this doesn't work is when using alloca()
or C99 var-sized arrays (IIRC C99 did add them). You could get around it
using placement-new syntax, but it's barely woth the hassle.
Uli
>> What you are essentially arguing is that *I* shouldn't use a
>> feature *you* don't understand
>
> No, that's not at all what I'm arguing. I'm arguing that the
> features are too complex so they end up being mis-understood
> and used to write broken code.
You can argue that feature X is too complex for you -- or even the
average programmer -- to understand and use, but that has no bearing on
my ability to understand and use that feature.
If you can't drive a nail without crushing your thumb to a bloody pulp,
that's too bad. But it doesn't mean that others can't, and your
inability shouldn't count against the rest of us.
> However, even though that wasn't my point, arguing that you
> should write code that's easy for others to understand is still
> a valid argument. Even if your code starts out correct, if
> it's too complex for other people to understand, it will end up
> broken just the same as if it were written by somebody who
> didn't understand the language features to start with.
OK, so your point is that we should just use BASIC and/or the
programming language that LEGO uses in their MindStorm series, to cater
to the worst programmer on the planet...
> Writing code that's easy to read and understand is arguably
> more important than writing correct code. Correct but complex
> code decays into brokenness. Easy to read code imporoves.
Of course "easy to read" code is more important that "correct code."
It's not like it matters whether a patient in a CT machine gets a dose
of 300 rems instead of 0.3 rems...
-n
>> s1 += s2 + "," + s3;
>>
>>That may be fine for application code where the coder (presumably)
>>knows when and how often it's going to be executed and can judge the
>>tradeoffs. But it's almost certainly a bad idea within the kernel.
>
> Why? It sounds like you are saying that user-mode coders are smart
> enough to worry about the memory implications of a statement like
> that, but kernel coders are not.
That's not what I was trying to say. I meant that there are virtually no
situations in kernel code where the inefficiencies associated with that
string expression can be tolerated while OTOH there are many situations in
user-mode code where the convenience and succinctness of such an expression
outweigh the inefficiencies.
GH
> OK, so your point is that we should just use BASIC and/or the
> programming language that LEGO uses in their MindStorm series, to cater
> to the worst programmer on the planet...
No. There are much, much simpler languages that are just as
powerful as C++. Modula-2/3, Python, Scheme, and Smalltalk for
example.
--
Grant Edwards grante Yow! I have the power to
at HALT PRODUCTION on all
visi.com TEENAGE SEX COMEDIES!!
They're just as powerful *for* *you* and you're welcome to use them,
but your needs don't dictate my tools, so I'll just keep using C++.
-n
This type of argument is perfectly representative of completely autistic
people. As soon as you collaborate in a team, you have to choose tools
that each member of the team can use successfully, and not baroque tools
that only afficionados can master. If you are using C++ in a project and
in particular "high falutin" features of C++, you are shoving down the
throat of each and any people in the project the obligation to learn
those features, wether they want it or not. From each report i have seen
the number of projects in the industry that have utterly failed because
some geek had the wonderful idea to introduce C++ in the game is
enormous. It is for good reasons that the Linux kernel developers have
banished C++ from their kernel. You are welcome to use esotery in you
work, they are welcome to use a language they see fit to their work,
and they collectively understand.
--
Michel TALON
This contradicts itself. They cannot be 'much simpler' and 'just as
powerful' at the same time, except if 'much simpler' actually means
'much simple for me [here meaning Grant Edwards], because I know them
already'.
This is not true, they can be both much simpler and as powerful if they
are well thought, while the other language is a bag of tricks assembled
in a random way.
--
Michel TALON
This statements doesn't make sense[*]. What C calls 'an object' is a
thing residing at some adressable memory location, allocated with a
certain storage duration, visible in some particular set of scopes
and being of a certain type. The term 'class' is not a defined part of
the C programming language.
[*] C++-terms cannot meaningfully applied to C in this way.
At best, they can serve as analogies.
But this wasn't the meaning of my statement, anyway. That was an
explanation why I consider the existence of default constructors, copy
constructors and destructors part of the implementation of a class and
not part of its interface.
>> I am somewhat uncertain about overloaded operators because the use
>> of the corresponding symbols is not specific to classes which
>> eventually overload them.
>
> Well, overloaded operators are pretty easy to spot, aren't they? I mean you
> only have so many fundamental types (for which there are already operator
> overloads in C) where you know that an operator is builtin. Everything else
> must be user-overloaded.
This increases the amount of context knowledge necessary to understand
the code at a particular text location: Is this now an addition or is
it a subroutine call or even some mixture of additions and subroutine
calls (eg some of the operands could be instances of classes defining
conversion routines to types having a +).
[...]
>>> And of course, when using objects of a class, you should be aware of
>>> the interface. OTOH when doing OOP using C, you have the same
>>> requirements, only that every call uses normal function syntax.
>>
>> That's the difference: To know that
>>
>> A a;
>>
>> causes a subroutine to be called (and is consequently likely a
>> non-trivial action), a reader needs to be aware of the definition of
>> the class A and of the definitions of all of its eventual members
>> having a class-type and their members and so on.
>>
>> A a;
>>
>> init_an_a(&a);
>>
>> makes this explicit.
>
> Yeah, and you forgot the error checking and cleanup (in every damn
> path).
In real-world C-code, there is no 'error checking and cleanup
in every damn path'.
[...]
>> Memory allocated by a constructor for use by the class until
>> destruction cannot be stack-allocated, because it would need
>> to be allocated in the strack frame of some caller having a suitable
>> lifetime.
>
> Well, then you put it as member into the class itself - that was
> easy.
Apparently, it wasn't. I was talking about constructors allocating
memory. You are talking about constructors not allocating memory.
These are two different things.
[...]
>> > There are much, much simpler languages that are just as
>> > powerful as C++. Modula-2/3, Python, Scheme, and Smalltalk for
>> > example.
>>
>> This contradicts itself. They cannot be 'much simpler' and 'just as
>> powerful' at the same time, except if 'much simpler' actually means
>> 'much simple for me [here meaning Grant Edwards], because I know them
>> already'.
>
> This is not true, they can be both much simpler and as powerful if they
> are well thought, while the other language is a bag of tricks assembled
> in a random way.
It is not trivial to correctly assess that. For instance, it took me
literally years of writing C to understand why post-increment and
pre-increment exist and even longer until I started to understand (and
use) the comma-operator. Somewhere it between those two fell the
moment where I suddenly realized why the pthread signalling model is
the way it is. It is very easy to confuse what one doesn't (yet)
understand with what is actually nonsense, especially, in areas where
one does not really have in-depth knowledge and experience (I know
this to be true for me and strongly believe it to be true for others
as well). This is the 'Dunning-Kruger'-effect referenced in another
posting in action.
`
...but people have in this thread mostly been repeating FUD and showing off
their dangerous half-knowledge, not those 'good reasons' as you say.
> You are welcome to use esotery in you work, [...]
Calling names? <sigh>
Uli
That would be the very 'good reason' Michael was originally writing
about if it was true.
It is not "calling names". If you want me to call names, for me C++ is the
ugliest languages since at least PL/1 which was of the same type of
"engineering compromise" designed by monkeys. It is a testimony to the intelligence
of Linux kernel developers (or BSD kernel developers) that they don't want to see
this stinking horror close to their work. People indoctrinated to beleive that there
is some reason in C++ can happily use it in Windows how much as they see fit.
They can even beleive it is a sharp tool or be confident in their superiority because
they have spent years learning Stroustrup Necronomicon.
>
> Uli
>
--
Michel TALON
Calling a tool for an engineer "esoteric" is calling names (I'm not a native
english speaker, and maybe I'm misunderstanding the meaning thereof) and a
personal attack on any engineer using it, because it questions the reasons
of said engineer for choosing that tool. In fact it questions their whole
ability to determine the right tool for a certain job.
[ ...more drivel, including a "buzz off and use Windows"...]
Okay, I think I understand you now.
sadly,
Uli
The people that I work with are all C++ experts; they would not have
been hired otherwise. It is the tool of choice in my work environment,
and it's served us very well.
I would probably use C++ in any new project that I undertook,
commercial or open-source, because I find the language to be powerful
and I am comfortable with it. I wouldn't be "shoving" anything "down the
throat" of anyone. After all I don't sit behind you, pointing a gun to
your head and forcing you to work with my code, and/or use or buy my
software.
> From each report i have seen
> the number of projects in the industry that have utterly failed because
> some geek had the wonderful idea to introduce C++ in the game is
> enormous.
I'm sceptical, especially since you provide no references. But even if
is true, then this tells us very little about C++ itself and its role in
the demise of the project. After all, most software projects are
unsuccessful. For every Linux, OpenOffice and GIMP, there are countless
other software corpses littering code repos of the world.
> It is for good reasons that the Linux kernel developers have
> banished C++ from their kernel.
Maybe so, but the reasons provided in this thread are clearly bogus.
> You are welcome to use esotery in you
> work, they are welcome to use a language they see fit to their work,
> and they collectively understand.
Yes, people should be able to use the tools they deem necessary, a
principle I stated long before you showed up in this thread. But you
said earlier that using C++ is "forcing" people and "shoving C++ down
their throat." So stop with the double-talk and answer the question: Can
I use the tool of my choice, just like the Linux kernel guys can, or
would that be me forcing others? And how would I be forcing them to do
anything?
-n
The 'class invariants' of struct fops is that all its function pointers are
either zero or point to functions that can handle the according requests.
Maybe 'class invariant' is not the 100% correct term, but that's beside the
point. Some objects must be initialised before use. C forces you to
remember this initialisation and perform it manually, while C++ allows the
designer of the object type to define these initialisations.
> But this wasn't the meaning of my statement, anyway. That was an
> explanation why I consider the existence of default constructors, copy
> constructors and destructors part of the implementation of a class and
> not part of its interface.
Hmmm, I'm not so sure about it. Certainly, as designer of a class, you have
lots of choice about which constructors and operators you provide. I know
quite some cases where objects are not copyable or assignable, and some are
not even creatable without certain arguments.
>> Yeah, and you forgot the error checking and cleanup (in every damn
>> path).
>
> In real-world C-code, there is no 'error checking and cleanup
> in every damn path'.
Two assumptions:
1. You allocate resources that require cleanup.
2. The time that resource is needed can be bound to the scope.
This means that if you don't want a resource leak, you _must_ trigger
cleanup in every code path.
Now, what the error-handling concerns, whenever you have a function that can
fail, you must check for errors, right? Typically, that involves checking a
returnvalue and forwarding that error to the calling function.
What this means is that you need error handling code (or, rather, error
forwarding code) for every function call that can fail and you need cleanup
code before every return statement. Since the error-forwarding code
typically uses a return statement, those two are mixed together.
Using 'goto' you can merge the two partially.
>>> Memory allocated by a constructor for use by the class until
>>> destruction cannot be stack-allocated, because it would need
>>> to be allocated in the strack frame of some caller having a suitable
>>> lifetime.
>>
>> Well, then you put it as member into the class itself - that was
>> easy.
>
> Apparently, it wasn't. I was talking about constructors allocating
> memory. You are talking about constructors not allocating memory.
> These are two different things.
I'm not getting it. Maybe you could give an example?
What I was thinking of was mostly like this:
// C
char buffer[MAX_PATH+1];
// C++
path buffer;
where 'path' is implemented like this:
// C++
struct path {
... // various memberfunctions
private:
char buffer[MAX_PATH+1];
};
Just in case you are not aware of it, construction of an object takes two
stages, one is reserving the memory (which can well be on the stack!) and
the second stage is invoking the constructor on that memory. You might
argue that it then is not the constructor allocating the memory but the
declaration or maybe the type, but I don't think that is what you meant
because it doesn't make a difference for the result but would be just
nitpicking at terminology. So what is it that you meant when you said a C++
object couldn't use stack-allocated memory? I think an example could be
helpful, those often help clearing such misunderstandings.
Uli
> This type of argument is perfectly representative of completely autistic
> people. As soon as you collaborate in a team, you have to choose tools
> that each member of the team can use successfully, and not baroque tools
> that only afficionados can master. If you are using C++ in a project and
> in particular "high falutin" features of C++, you are shoving down the
> throat of each and any people in the project the obligation to learn
> those features, wether they want it or not.
Nothing about the choice to use C++ requires you to use any particular
features. So this argument *CANNOT* affect the decision to use C or C+
+.
You can write code that other people can't understand in C too.
> From each report i have seen
> the number of projects in the industry that have utterly failed because
> some geek had the wonderful idea to introduce C++ in the game is
> enormous.
So because other people have abused a choice, I should not be allowed
the choice? Is that the UNIX way?
> It is for good reasons that the Linux kernel developers have
> banished C++ from their kernel. You are welcome to use esotery in you
> work, they are welcome to use a language they see fit to their work,
> and they collectively understand.
Nobody said otherwise.
DS
[ nothing ]
Since I am not even opposed to C++, I am not going to further serve
as 'point where a C++ advocacy campaign can be attached'.
[...]
> The people that I work with are all C++ experts; they would
> not have been hired otherwise.
This doesn't address Michael's claim at all, because he was very
clearly talking about the situation when a _new_ person becomes part
of an _existing_ team which is not comprised of people that were
specifically hired because 'being a C++ expert' was an important
consideration (and BTW, the language isn't that complicated).
> I would probably use C++ in any new project that I undertook,
> commercial or open-source, because I find the language to be powerful
> and I am comfortable with it.
In other words: You happen to know C++ and therefore, you would
perferably use it for everything. Selecting a programming language
without consideration for the task to be accomplished is at best a
dubious practice. Especially, taking into acocunt that an abundance
of more powerful languages exist (here refering to all the
bytecode-based languages), which are suitable for an ever-growing
range of tasks due to increased processing power of 'commonly used
hardware'.
[...]
>> From each report i have seen the number of projects in the industry
>> that have utterly failed because some geek had the wonderful idea
>> to introduce C++ in the game is enormous.
>
> I'm sceptical, especially since you provide no references. But
> even if is true, then this tells us very little about C++ itself and
> its role in the demise of the project. After all, most software
> projects are unsuccessful.
This kind-of misses the point. The claim was that a extraorinary large
number of C++-using projects were unsuccessful (which may or may not
be true). Your statement that 'most software projects are
unsuccessful' would, for instance, still be true if projects using C++
always failed and using C++ was attempted for most projects.
>> It is for good reasons that the Linux kernel developers have
>> banished C++ from their kernel.
>
> Maybe so, but the reasons provided in this thread are clearly
> bogus.
This is 'clearly' a matter of opinion and different people come to
different conclusions in this regard, eg if the 'hidden subroutine
calls' are an advantage or a disadavantage.
>>> This type of argument is perfectly representative of completely
>>> autistic people. As soon as you collaborate in a team, you have to
>>> choose tools that each member of the team can use successfully, and
>>> not baroque tools that only afficionados can master. If you are
>>> using C++ in a project and in particular "high falutin" features of
>>> C++, you are shoving down the throat of each and any people in the
>>> project the obligation to learn those features, wether they want it
>>> or not.
>
> [...]
>
>> The people that I work with are all C++ experts; they would
>> not have been hired otherwise.
>
> This doesn't address Michael's claim at all, because he was very
> clearly talking about the situation when a _new_ person becomes part
> of an _existing_ team which is not comprised of people that were
> specifically hired because 'being a C++ expert' was an important
> consideration (and BTW, the language isn't that complicated).
What was suggested, and the point that I was trying to rebuff, is that
we should write code for the lowest common denominator, because to do
anything else would be to "shove down the throat of everyone the
obligation to learn these [advanced] features."
As for the new person coming onto a team: when someone decides to study
to become a heart surgeon, he doesn't complain that performing heart
surgery is hard and that the method shouldn't be shoved down his throat
because stents and medications work very well, so we should just stick
with those.
>> I would probably use C++ in any new project that I undertook,
>> commercial or open-source, because I find the language to be powerful
>> and I am comfortable with it.
>
> In other words: You happen to know C++ and therefore, you would
> perferably use it for everything. Selecting a programming language
> without consideration for the task to be accomplished is at best a
> dubious practice. Especially, taking into acocunt that an abundance
> of more powerful languages exist (here refering to all the
> bytecode-based languages), which are suitable for an ever-growing
> range of tasks due to increased processing power of 'commonly used
> hardware'.
I never suggested that I would _indiscriminately_ choose C++. I said I
would _probably_ use it, and I gave my reasons why -- it is a powerful
language that I know very well. Most importantly, it is well suited to
the projects that I usually work with.
But it is a trade-off: While I don't normally use a screwdriver to stir
paint, I would if I absolutely had to finish painting and getting a
paint stirrer meant wasting 30 minutes to drive to Home Depot.
It is the same with programming: MUMPS might be the perfect paint
stirrer, but if I don't have the time to drive to the Home Depot, I'm
going to reach for my trusty multicolored C++ screwdriver, pop the can
and get painting.
>>> From each report i have seen the number of projects in the industry
>>> that have utterly failed because some geek had the wonderful idea
>>> to introduce C++ in the game is enormous.
>> I'm sceptical, especially since you provide no references. But
>> even if is true, then this tells us very little about C++ itself and
>> its role in the demise of the project. After all, most software
>> projects are unsuccessful.
>
> This kind-of misses the point. The claim was that a extraorinary large
> number of C++-using projects were unsuccessful (which may or may not
> be true). Your statement that 'most software projects are
> unsuccessful' would, for instance, still be true if projects using C++
> always failed and using C++ was attempted for most projects.
I don't think this misses the point at all. It is a fact that most
software projects, _regardless of the language used_, fail. It's unfair
to attribute that failure to the language itself without justifying that
attribution, something that the OP did.
>>> It is for good reasons that the Linux kernel developers have
>>> banished C++ from their kernel.
>> Maybe so, but the reasons provided in this thread are clearly
>> bogus.
>
> This is 'clearly' a matter of opinion and different people come to
> different conclusions in this regard, eg if the 'hidden subroutine
> calls' are an advantage or a disadavantage.
Of course different people come to different conclusions, especially if
some start off with flawed premises, like that whole "constructors are
hidden subroutine calls" bit.
But that is not the issue.
-n
You cannot possibly 'rebuff the point that code should be written to
the lowest common denominator' by stating that 'the lowest common
denominator' in 'your team' is actually you (among others, if all are
equally qualified).
> As for the new person coming onto a team: when someone decides
> to study to become a heart surgeon, he doesn't complain that
> performing heart surgery is hard
The case you present is the exact opposite of the case presented: I
was writing about someone being a 'C++ expert' joining a team of
people who are not. You appear to be writing about someone not being
'a C++-expert' joining a team of 'C++-experts'.
[...]
>>> I would probably use C++ in any new project that I undertook,
>>> commercial or open-source, because I find the language to be powerful
>>> and I am comfortable with it.
>> In other words: You happen to know C++ and therefore, you would
>> perferably use it for everything. Selecting a programming language
>> without consideration for the task to be accomplished is at best a
>> dubious practice. Especially, taking into acocunt that an abundance
>> of more powerful languages exist (here refering to all the
>> bytecode-based languages), which are suitable for an ever-growing
>> range of tasks due to increased processing power of 'commonly used
>> hardware'.
>
> I never suggested that I would _indiscriminately_ choose
> C++. I said I would _probably_ use it, and I gave my reasons why -- it
> is a powerful language that I know very well.
And I responded to this that 'properties of you' should be a secondary
criterium when picking a programming language, because 'properties of
the task' would be more important.
[...]
>>>> From each report i have seen the number of projects in the industry
>>>> that have utterly failed because some geek had the wonderful idea
>>>> to introduce C++ in the game is enormous.
>>> I'm sceptical, especially since you provide no references. But
>>> even if is true, then this tells us very little about C++ itself and
>>> its role in the demise of the project. After all, most software
>>> projects are unsuccessful.
>> This kind-of misses the point. The claim was that a extraorinary
>> large
>> number of C++-using projects were unsuccessful (which may or may not
>> be true). Your statement that 'most software projects are
>> unsuccessful' would, for instance, still be true if projects using C++
>> always failed and using C++ was attempted for most projects.
>
> I don't think this misses the point at all. It is a fact that
> most software projects, _regardless of the language used_, fail.
As I have written: This does not matter and you are missing the point
or avoid to address it. The interesting question would be 'what is the
percentage of failed C++ projects, compared to the percentage of
failed projects using different languages'.
NB: I do not claim anything that it would be anything in
particular.
[...]
>>>> It is for good reasons that the Linux kernel developers have
>>>> banished C++ from their kernel.
>>> Maybe so, but the reasons provided in this thread are clearly
>>> bogus.
>> This is 'clearly' a matter of opinion and different people come to
>> different conclusions in this regard, eg if the 'hidden subroutine
>> calls' are an advantage or a disadavantage.
>
> Of course different people come to different conclusions,
> especially if some start off with flawed premises, like that whole
> "constructors are hidden subroutine calls" bit.
Taking this 'interesting' statement into account, I hereby formulate a
hypothesis which may throw an indirect light onto 'The C++ programing
language': It strongly appeals to logic-impaired people with an
intuitive or explictly acquired understanding of propagande tactics
they freely use to further their respective causes (like faking proofs
by redefining terms in a suitable way).