Kuro5hin.org: technology and culture, from the trenches
create account | help/FAQ | contact | links | search | IRC | site news
[ Everything | Diaries | Technology | Science | Culture | Politics | Media | News | Internet | Op-Ed | Fiction | Meta | MLP ]
We need your support: buy an ad | premium membership

[P]
The C++ Programmer's Bag of Tricks

By carbon in Technology
Thu Jul 18, 2002 at 08:36:45 AM EST
Tags: Technology (all tags)
Technology

Developers new to C++ may find themselves unable to do things that used to be facilitated by the built-in standard libraries of another language. Other than the Standard Template Library with which you should already be familiar, C++ does not come with a comprehensive set of general tools and libraries. However, this is where other people's code comes in!

The tools presented here are applicable to many programming tasks, not just to a specific area. They run on many platforms, so more people can use or contribute to your project. They are efficient, actively improved, well documented, and cleanly designed. They are implementations of the wheel to make it easy for you to build a snazzier convertible.

They are just members of the C++ programmer's bag of tricks.


Introduction

C++ isn't perfect, but it can often be the right tool to use for several different types of jobs. C++ has a lot of practical language features, such as templates, functors, operator overloading, pointers, and multiple inheritance. Java, for example, does not implement any of the above things in its current incarnation.

One of the things that Java is better at than C++, however, is providing high-level tools as part of the language itself. Threading, regular expressions, GUIs, and many other features are all inside Java's API. At first glance, a similar set of tools seems to be lacking in C++, as its standard library contains only the bare basics, as well as the STL's useful containers, iterators, and algorithms. For example, C++ does not implement any threading in and of itself, despite threads being an important part of quite a few large projects.

But, C++ does have a large public code repository available for your use at the other end of a Google search. Deciding which of several similar libraries to use can be difficult, and there's always the occasional unpleasant discovery of a library not living up to its own specifications. This article tries to take some of the hard work out of a new C++ developer's life, and list a few projects that are known to be well-built. I've compiled this list partially on my personal experiences, but mostly based on the suggestions of various experienced developers in the Open Projects channel #C++.

So without further ado, the list:

Lua : The extensible extensions language

Lua is a tiny and highly efficient scripting language. It was designed from the very start to do nothing but be used for extending C or C++ programs. Since Lua is written in pure ANSI C, it's extremely portable. But the best feature of Lua may be its unbridled speed.

Lua isn't perfect, and it's C-ness comes at somewhat of a price. It's API is very typical of C libraries, in that all the functions are global and in the form lua_<something>. It uses regular function pointers for call backs, which means that you cannot set a call back to a method of a particular instance without designing around it within the Lua code itself. For example, you could have each call back require a pointer or some other sort of global object identifier, or build some sort of global wrapper around C++'s pointers-to-members.

Lua code itself is written in a clear and easy-to-understand language. I would describe it as a cross between BASIC's syntax and Scheme's first-class functions. It also provides some simplistic object oriented facilities, somewhat reminiscent of Perl's OO. Also, Lua does not have direct access to your C++ code; it can only access the external world through Lua extension libraries and call backs that you provide.

This combination of portability, speed, and simplicity all make Lua useful in a wide range of situations. You could use it in your project which must execute scripts so often that the overhead of larger languages becomes unwieldy. Or, you could use it to allow people without extensive programming experience to still extend your program to fit their needs. You could even use Lua to for either of these features while working on a system where resources are limited or with obscure portability requirements, such as a PDA or embedded network appliance.

So to conclude, Lua is, under many but not all circumstances, a good alternative to larger scripting languages such as Python. If you find Lua is too simple for your needs, though, Python is another good choice for an extensions language. Boost implements a very impressive Python API, allowing it to extend your app in an object oriented fashion. And speaking of Boost...

Boost : The handy library of handy libraries

Boost is probably the largest and most active general purpose C++ library available. It was founded by members of the C++ Standards Committee as a testing ground for new libraries, supposedly for eventual placement into the language itself. Each library submitted to Boost goes under a rigorous testing process before being admitted, and all the ones currently in the library are polished and useful.

Much of Boost is implemented entirely in headers. These usually include simple class constructs that eventually tend to show up, in one form or another, in a number of large projects. For example, there's the noncopyable utility class to prevent certain types from being copied, and the tuple library, a template for holding some specific set of objects in a single container.

Some mathematical libraries are also part of Boost. Cstdint implements some simple number classes, both guaranteed-size integer types which stay the same across different platforms (as with the C header stdint.h), and numbers designed to scale as needed to hold extremely large values. There is also the common factor library for simple LCD and GCD calculations, as well as more complex mathematical concepts like octonions, quaterions, and rational numbers.

There are also Boost libraries for further extending basic C++ features. Smart_ptr contains more flexible and specialized versions of the standard library's auto_ptr, letting you define ownership more precisely. The operators library allows you to have operators built automatically based upon other operators that you've written (for example, automatically defining not-equals based upon equals, or turning less-than and equals into the complete set of comparison operators.) Another useful library is Boost's array, which has a template class designed to give all the efficiency of the fixed C array with additional safety and sanity checks. Even more Boost libs include Static_assert for compile-time assertions, and ref which allows things you couldn't normally do with references, such as feeding them into template algorithms. Also, the concept checking library allows you to more effectively ensure that class interfaces you use and write meet their contracts concerning time complexity, valid expressions, and other such things. And finally, the conversion library provides some primitive conversions that normally require the usage of stringstreams or special library calls to perform.

Boost also contains a regular expressions library. Regular expressions are a powerful way of doing string processing of nearly all kinds besides tokenization, which Boost has a library for as well. The standard C++ library does have some regex-like features (such as the various basic_string find functions), but they aren't comparable to proper regular expression support. Th Boost regex library provides many of the general operations such as match, replace, and split, all of which are dear in the hearts of Perl developers everywhere.

In the Lua section above, I mentioned that Boost had a Python interface. While it's true that Python already comes with a C/C++ API, the Boost Python interface is in a different type of class (if you'll excuse the bad pun) altogether. The regular Python interface permits you to manually control the Python system like any other library, while Boost Python reverses this and allows Python to access and even extend C++ classes as though they were Python classes. It's very easy to grant Python scripts access to your C++ classes, and in doing so you just make it that much simpler for others to expand your code without even having to compile anything.

The final Boost offering I'd like to look at is the thread library, a portable implementation of concurrency. Threading is the thing to use if you want your app to run efficiently across multiple processors, under complex schedulers, with faster responses to new events, or just to separate the real-time and external interface parts of your library. Threading is covered by a wide range of techniques and literature, so if you're familiar with those techniques, consider taking advantage of the Boost thread library's portability and safety.

Believe it or not, there's more. The list of continues with even more useful Boost libraries that aren't discussed above. One of those libraries, any, actually has another Kuro5hin story dedicated entirely to it.

You may find that your use of Boost classes becomes so regular as to make them seem like C++ libraries. This is easy enough to do, since they're built upon the same principles of generic programming and reviewed by many of the same people who set up the C++ standard library. But now that your project is starting to depend upon more complex and powerful external code, it may reach a higher degree of complexity then you expected. If you want to keep track of your overall design, or easily explain your library's API to other developers, you should use a good documentation system, such as...

Doxygen : The comment-parser worthy of comment

Doxygen is an API documentation system, designed in the same style as the documentation systems for Java, Perl, and Python: the docs that are generated are actually based off the comments in your source code. Doxygen has the advantage of being rather more flexible then the majority of such programs. In addition to a wide array of output formats, it can support practically any comment style you'd want to use, including those that work well in the C++ world of separate headers and implementations.

Doxygen isn't only a C++ tool; it works with C, Java, IDL, and PHP, and could probably be extended to others. In addition, it generates not only HTML, but also LaTeX, PostScript, PDFs, and even UNIX man pages. Besides this, it can understand and beautify things like dependencies and collaborations, formulas, and especially detailed and nice-looking versions of the standard class hierarchy diagrams we all love so much. Because the documentation goes right into the relevant source code, it's more difficult to forget to update your docs to match your program's evolution.

Now, your project is really cooking; other coders can use your classes in their projects, and contribute to your own code, because they can easily see what you're thinking of with your design. The next step might be to add network access of some kind, so that something can control or be controlled by your program remotely. One way to do that in a non-platform-specific way is with...

ACE : Adaptive, layered networking which just works

ACE is a collection of components, patterns, and wrappers which give your projects an adaptive way of talking with other networked apps. This is really a gross over-simplification; ACE provides more networking services then you can shake an inheritance tree at, including a related CORBA implementation, its own threading system, signal handling, IPC, message routing, containers, iostreams, a POSIXish OS adaption layer, and far more besides.

To do ACE justice on Kuro5hin would necessitate a separate story altogether, so curious programmers should read the overview, and (after their heads are suitably spinning) work through some tutorials.

But now your project is getting even more complex, especially with the possible introduction of concurrency issues, either via networking or threading. What you really need now is a way of getting rid of all those lingering bugs you can just sense lying beneath the calm waters of your class interfaces (I'm really on a roll with these bad analogies, aren't I?). Luckily for you, there's...

Libcwd : The debugger that helps you help your own code

Libcwd is a debugging support library, which has features like automated memory debugging, runtime support for printing file and line number information, and human-readable demangled typenames. It's thread safe, allows for the creation of multiple debug channels (the named frontends for debugging output) and debug devices (ostreams for actually delivering the debugging data), all of which can be turned on and off dynamically on a per-thread basis. In addition, Libcwd can automatically watch for memory allocations and certain other types of events, helping you to remove memory leaks. What all this allows you to do is to get a real-time display of whatever part of your application you're interested in at the moment, as it runs.

Among all of Libcwd's features, though, perhaps the most useful property of Libcwd is that it's easy to get rid of. When making a release of your application, you can avoid compiling in Libcwd simply by undefining a preprocessor macro and not linking to Libcwd. Since all the actual debugging code is accessed via carefully designed preprocessor macros, compiling your app without them will remove all trace of the any additional dependencies, portability restrictions, and efficiency problems associated with the actual debugging code.

The main disadvantage in using Libcwd is that, in itself, it isn't portable beyond g++, the GNU C++ compiler, and UNIX-ish operating systems, or in some cases only Linux. Your actual release code will be, though, which also means you can simply have some developers use it without affecting the portability of the project's code itself at all. Your developers using Linux will still reap its benefits.

Sponsors

Voxel dot net
o Managed Hosting
o VoxCAST Content Delivery
o Raw Infrastructure

Login

Poll
What do you think of these tools?
o They sound very useful, I'll check them out more closely 32%
o I've already been using some of these in my projects 26%
o I use other tools to accomplish the same tasks these do 3%
o Real Programmers code their own standard libraries 6%
o I don't even like C++, stop bugging me 23%
o I'm not a programmer, what the heck is this stuff? 6%

Votes: 89
Results | Other Polls

Related Links
o Kuro5hin
o Google
o Standard Template Library
o Java's API
o a Google search
o Open Projects
o Lua
o API
o language
o Perl's OO
o good alternative
o Python
o Boost
o noncopyabl e
o tuple
o Cstdint
o common factor
o octonions
o quaterions
o rational
o Smart_ptr
o operators
o array
o Static_ass ert
o ref
o concept checking
o conversion
o regular expressions
o a library
o Python [2]
o a C/C++ API
o very easy
o thread
o safety
o even more useful Boost libraries
o any
o another Kuro5hin story
o Doxygen
o LaTeX
o ACE
o CORBA implementation
o overview
o tutorials
o Libcwd
o g++
o Also by carbon


Display: Sort:
The C++ Programmer's Bag of Tricks | 190 comments (172 topical, 18 editorial, 2 hidden)
Whew! That sounds like a lot of work! (3.30 / 42) (#4)
by Steve Ballmer on Thu Jul 18, 2002 at 04:07:47 AM EST

Why not take the fuss out of programming and switch to Visual C# .NET?

Those of you looking to upgrade your programming skills from C or C++ to C# are invited to attend Microsoft's C# Summer Camp from August 19th through 23rd, right here in Redmond!

Each morning kicks off with a general assembly led by the Microsoft C# Development Team. You'll then attend sessions written and taught by the DevelopMentor .NET team of instructors. You'll create your own curriculum, choosing from 36 session titles with tracks ranging from the common language runtime (CLR), XML Web services, and Microsoft ASP.NET. You'll have a chance to try what you're learning and ask questions during scheduled lab sessions with instructors on-hand. By the end of the week, you'll be ready start writing .NET-based applications.

But C# Summer Camp is not all about work--there is plenty of play involved, too. Code competitions, hiking, team sports, golf, and a BBQ cookout are some of the extra-curricular activities you can participate in alongside members of the Microsoft C# team.

Heh (4.00 / 6) (#5)
by carbon on Thu Jul 18, 2002 at 04:21:07 AM EST

I've never seen a troll before that didn't irritate me, but just amuse me. The nice thing about Steve Ballmer's K5 alter-ego is it's hard to say if he's just quoting from M$'s site directly, or subtely mocking them, or perhaps both. Keep up the good trolling!

But C# Summer Camp is not all about work--there is plenty of play involved, too. Code competitions, hiking, team sports, golf, and a BBQ cookout are some of the extra-curricular activities you can participate in alongside members of the Microsoft C# team.

Code competitions, eh? I rather think they'd have a hard time living up to the bastion of nifty that is Perl Golf. As for those other things... weren't you trying to appeal to coders? I hope you have Half-Life or Worms World Party under the "team sports" category, or it'll be a long and silent night and you'll have to clean up all the drinks and food afterwords. :-)


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
great deal! (4.00 / 1) (#6)
by zephc on Thu Jul 18, 2002 at 04:23:56 AM EST

only $1900 to hang with Microserfs!  thanks for the tip, Steve!

=P

[ Parent ]

M$FT has their head in their *ss (2.60 / 5) (#44)
by straightforward on Thu Jul 18, 2002 at 12:10:20 PM EST

C# is currently a poor copy of Java.  Just like everything else, M$FT had to beg, borrow, steal, or buyout anything of percieved value that ever came out of Redmond.  If they ever really found out how to capitalize on all those research dollars, we really would have something to worry about.

The recent Fortune article summed it up beautifully in Gate's own words that M$FT research was basically a source of daily curiosity for the *man*, and that was it.  Wow, a floating mouse, Wow, 20 virtual screens on one box, Wow, a talking virtual receptionist, Whoopie do.  They should tie research to market vision and potential revenue to standards realization before they waste our time.  The wind has changed and they haven't realized that their market share will only increase by accepting and asserting common standards instead of reinventing anything at this point.  Oh, but I forgot this is a big pissing contest, nothing more.

If M$FT was really clever in this case, they would have imported the Java spec onto the .NET abstraction and leveraged knowledge share, market dominance, while saving themselves a ton of money in the process, all the while polishing their tarnished image to boot.  The value in developer confidence would have been worth it alone.  Once again, they have simply polarized knowledge share, not even necessarily to their benefit.

...

[ Parent ]

YHBT. YHL. HAND (2.50 / 2) (#57)
by rasactive on Thu Jul 18, 2002 at 02:41:19 PM EST

Link, so it will be straightforward enough for ya

[ Parent ]
C# (3.00 / 2) (#69)
by ucblockhead on Thu Jul 18, 2002 at 03:40:42 PM EST

I've found it to be a pretty good copy of Java. It has some improvements that Java would do well to copy.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
Such as??? (3.00 / 2) (#94)
by straightforward on Thu Jul 18, 2002 at 05:32:57 PM EST

Examples?

[ Parent ]
A few examples (3.00 / 2) (#103)
by ucblockhead on Thu Jul 18, 2002 at 06:01:53 PM EST

Properties. Implicit casting. Operator overloading. Indexes.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
A few more examples (3.00 / 2) (#106)
by Carnage4Life on Thu Jul 18, 2002 at 06:43:18 PM EST

Boxing. Enums. Foreach. Pass-by-reference

[ Parent ]
Boxing (none / 0) (#108)
by ucblockhead on Thu Jul 18, 2002 at 06:49:34 PM EST

I personally thing the whole boxing concept is a bit broken mostly in that I suspect that the fact that it gets done implicitly will cause nasty bugs. (Which I admit, I have not yet run into.)

I also thing that it is a bit broken that the language allows code like this:

Image.Image = new Image();

Especially given that they explicitly disallow locals that hide other locals on the grounds that it can cause confusing code.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

ok... (none / 0) (#148)
by straightforward on Fri Jul 19, 2002 at 11:42:49 AM EST

Boxing - Have to give it up for the coolness factor of boxing, although the true typesafety of transportable assemblies has yet to be tested in the real world b/c of the single platform nature of .NET

Enums - subjective, can be accomplished many other ways.  Don't need a seperate type for it.

Foreach - Coolness factor, love it in perl, still not necessary though, and not revolutionary.

Pass-by-Reference - for basic types, very cool, if only for the polymorphism on typed output that it affords.  Otherwise, big deal.

[ Parent ]

ok... (none / 0) (#146)
by straightforward on Fri Jul 19, 2002 at 11:34:04 AM EST

Properties - Hmm, if I slice the grapefruit sideways instead of top/down, guess what, still have a sliced grapefruit.  This is syntactical only.  Only percieved value would be to wrap with parens and use as a value test in a conditional, which could also be accomplished in Java.

Implicit Casting - This simply supports laziness.  I like to be more explicit, but of course it is subjective.

Opertator Overloading - One that can lead to really wierd errors, it was omitted for a reason.  What do you do when you link utility classes between extensive business frameworks that both made explicit use of operator overloading?  You add a couple of weeks to the schedule.

Indexes - I am assuming that you are referring to 'Indexer'(s).  Hmmm.  Mixed reviews, the jury is still out on that one, although initial impressions were that it only confuses explicity Object types.

[ Parent ]

Whatever (5.00 / 1) (#152)
by ucblockhead on Fri Jul 19, 2002 at 01:42:53 PM EST

Then don't use it. Fuck if I care what language you use...

Just don't say something is a "poor copy of Java", when it is actually a pretty decent copy of Java.

(You underestimate the value of syntactic sugar, though.)
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

What bothers me about programming (3.50 / 2) (#60)
by whojgalt on Thu Jul 18, 2002 at 02:50:27 PM EST

Why not take the fuss out of programming and switch to Visual C# .NET?
That's what has always bothered me about programming: the fuss. All that darn fussing around, it's such a chore. Sound's like C# makes programming a joy again! And it makes my code sparkle!

C#: the Swiffer Wet-Mop of programming!

Best. Troll. Ever.
~~~~~~~~~~~~~~~~~
If you can't see it from the car, it's not really scenery.
Any code more than six months old was written by an idiot.
[ Parent ]

C++ sucks (2.66 / 9) (#19)
by marcos on Thu Jul 18, 2002 at 06:47:37 AM EST

And I use C++ as my language of choice. The fact of the matter is that there are things you do in C++ that you should not be doing. Garbage collection, typecasting, playing with ptrs to strings, etc. You can enhance this experience by using such libraries like those described above, but if you learn to use and love a particular set of libraries, and someday have to work somewhere where these libraries are not used, you suddenly become innefficient, and a bit lost.

Nowadays, I never program my UI with C++ any more. Simply too much work. Rather, I encapsulate all low level functionality in COM controls, and do not use any libraries (part from ATL, of course) for the controls. I get code reuse, all the flexibility and power of C++, as well as the ease of use of high level languages to design my UI and user interation with.

Java is a small step in the correct direction, but  it executes way too slow, and requires runtimes that are too bulky and system intrusive.

.NYET will probably take me out of my misery, but the runtimes are simply too big for me to program anything with them. Perhaps in 3 years, when the runtime is finally in every home, I'll get on the  bandwagon.

You know you're an expert in a language/platform (3.66 / 3) (#26)
by jolly st nick on Thu Jul 18, 2002 at 08:05:33 AM EST

when you move from love to hate.

[ Parent ]
In anger... (4.00 / 2) (#30)
by bsletten on Thu Jul 18, 2002 at 08:54:44 AM EST

There is a lovely phrase that I've seen mostly from folks in the U.K. dealing with this. It is "using something in anger". I'm guessing that the idea is that you know something so well that you are familiar with the negative aspects of it but use it anyway (because of a lack of alternatives, circumstances or familiarity).

[ Parent ]
Not my take. (4.00 / 1) (#31)
by pwhysall on Thu Jul 18, 2002 at 08:58:52 AM EST

When you use something in anger, you're past the testing stage and are using it to do real work.

"I've played with Debian Linux but I've never used it in anger" is an example.
--
Peter
K5 Editors
I'm going to wager that the story keeps getting dumped because it is a steaming pile of badly formatted fool-meme.
CheeseBurgerBrown
[ Parent ]

Hmmm... (none / 0) (#96)
by bsletten on Thu Jul 18, 2002 at 05:44:55 PM EST

That's what I intended to suggest the meaning to be. You phrased it more clearly, but I think the intent is the same. Let me try again: To use something "in anger" seems to mean that you've learned it well enough to know its shortcomings (beyond the testing stage) but are still able to do useful work with it. Unless "in anger" is just poetic license for "in earnest". It's a great phrase nonetheless.

[ Parent ]
I'm not sure about that (4.00 / 1) (#32)
by sien on Thu Jul 18, 2002 at 08:59:20 AM EST

I'm an Australian and I've heard the phrase being 'used in anger' to describe if a weapon had been used in practice, or really fired 'in anger'.

[ Parent ]
I think you're right (none / 0) (#137)
by x31eq on Fri Jul 19, 2002 at 07:38:00 AM EST

It does have the more general meaning in the UK, but I think the origin is as you say.

[ Parent ]
Managed C++ (4.00 / 4) (#29)
by Silent Chris on Thu Jul 18, 2002 at 08:48:53 AM EST

A lot of what you mentioned (GC, for example) is "fixed" with Managed C++.  It's still a bastard language (a mix of C, standard C++, Java, and a little C#), but at least mistakes are harder to create.

Personally, I like .NET.  The tradeoff in having huge runtimes (I think each person needs to download 15-20 megs), is that the actual executables are really small.  I programmed a simple label printer program, my first in .NET, with a complete Windows GUI in under 16K.  And that was in Visual Basic, of all things (bleah).  Assuming other platforms get on the table, the runtimes should be a non-issue (think how many people need to download and install some kind of Java runtime).

[ Parent ]

"Managed C++" (4.00 / 3) (#48)
by ucblockhead on Thu Jul 18, 2002 at 01:20:16 PM EST

Managed C++ is a horrendous joke. It's only worthwhile to save old C++ code. "Managed C++" has all of the disadvantages of C++ with none of the advantages. You are much, much better off simply going to C#.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
Languages (none / 0) (#70)
by jmzero on Thu Jul 18, 2002 at 03:43:52 PM EST

I kind of like C# - but I can't think of anything I'd use it for right now.  It makes programs that work, just like everything else.

All in all, I find it doesn't really matter what I'm programming in.  I'll do anything, really -but I'm tired of learning new object models.  The .NET object model makes sense for the most part.  Some parts of it are even intuitive.  

But I still have to look around a bit, and try this or that before I can do the simple things I need to do.  I get tired of learning new ways of doing the same things.  I guess I'm getting old.
.
"Let's not stir that bag of worms." - my lovely wife
[ Parent ]

Managed C++ (none / 0) (#105)
by ucblockhead on Thu Jul 18, 2002 at 06:19:50 PM EST

I'm not talking about .NET, but managed C++. Having done both, going from C++ to C# is easier than going from C++ to Managed C++.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
I'm just babbling... (none / 0) (#107)
by jmzero on Thu Jul 18, 2002 at 06:43:22 PM EST

But I agree that Managed C++ looks to be an odd beast.  It wasn't too far into reading about it that I decided "This is a language I will avoid."

As going with my thought before, I just don't want to know.  Maybe it's good, but it looks like it will take too many hours from my life to ever find that out.  It also looks as though it isn't really going to be an MS poster child like C#, so hopefully I'll ever run into a place I really need to use it.
.
"Let's not stir that bag of worms." - my lovely wife
[ Parent ]

Just an aside. (4.50 / 4) (#111)
by mindstrm on Thu Jul 18, 2002 at 07:19:41 PM EST

Without getting into faster/slower better/worse arguments.

If you don't want to deal with pointers, and garbage collection, then you are wanting something automated. When you automate something, you sacrifice control. WHen you sacrifice control, you sacrifice overall performance.

The same goes when you use, say, C instead of assembler. (No, this is not an 'assembly is better' speech). You trade control for ease of use. The compiler optimizes, yes, but a knowledgable human will be able to do better, even if it takes a long time.

The same goes when you go from C to C++. You lose some conrol over what's going on in exchange for some higher level logic (objects, etc). The C++ compiler optimizes, yes, but still perhaps not as good as if you built the project in C.

You go from C++ to Managed C++ or Java or something (nevermind the VM for now) and again, you gain functionality and ease of use, and lose some fine grained control over how the machine actually uses things, and leave it up to the compiler.

It's always a tradeoff between ease of use and maximum control. Always.

I know of people who prototyped projects in c++, then re-write them in C for a speed boost. This makes sense.

[ Parent ]

very useful (3.00 / 2) (#35)
by alyosha1 on Thu Jul 18, 2002 at 09:57:26 AM EST

I haven't used the other tools that you mention, but I find both doxygen and the boost libraries very useful, well designed tools. I now comment all my code doxygen-style by default, and it certainly impresses other people in my group when I present them with a set of web pages completely documenting all my code. First and foremost, however, the STL is the essential tool for any C++ programmer. I'm currently re-writing some of a co-worker's C code in C++, and it's very nice to replace a dozen lines of linked list-handling code with a single std::list<>

err.. (2.75 / 4) (#37)
by turmeric on Thu Jul 18, 2002 at 10:02:25 AM EST

and i suppose doxygen, ace, and libcwd all work perfectly together? no 'oh youre using ACE threads so the output will be meaningless'?

the most important tool in a programmers tool box is her brain, and her ability to communicate with the users.

yup! (4.00 / 2) (#39)
by avdi on Thu Jul 18, 2002 at 10:46:23 AM EST

Well, I can speak from experience about using boost, ACE, and Doxygen all at the same time anyway.  They work fine together, and complement each other well.  As a matter of fact, the ACE project has taken to using Doxygen for documentation.

Oh, and the line about ACE having it's own threading system was misleading.  One of the things ACE provides is a set of generic "wrappers" for threads (actually, for just about all services which vary from system-to-system).  This enables me to write multi-threaded networking code in C++ which Just Works regardless of what platform it's compiled on.  This isn't just marketing either; where I work this capability is used every single day.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

Sorry about that (none / 0) (#84)
by carbon on Thu Jul 18, 2002 at 04:47:45 PM EST

Sorry if that was confusing. It just seems patently silly to me to implement a threading system within the language itself, so I hadn't considered it, but now I suppose there might be conditions under which you'd do that (such as implementing sub-threading on an extremely simple embedded OS). As you said, ACE's threads just provide an interface to the OS's threading system, just as with Boost's thread library.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
It may sound silly... (none / 0) (#115)
by avdi on Thu Jul 18, 2002 at 07:41:36 PM EST

...but that's the way threading works in the Ruby language, and it's not the only one.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]
Well (none / 0) (#85)
by carbon on Thu Jul 18, 2002 at 04:51:07 PM EST

Libcwd understands threading in general, you just need to implement pipes for it in whatever threading system you're using (pthreads, Boost threads, ACE threads, yarn threads, string threads, er..). This is just from reading the libcwd documentation though, I haven't used libcwd and threads at the same time in my code.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Just for the record... (4.66 / 3) (#38)
by mcherm on Thu Jul 18, 2002 at 10:38:01 AM EST

Let me say, just for the record, "Thanks for posting this!" It was informative, useful, and technical while still being easy to understand.

-- Michael Chermside
Thanks! (4.00 / 1) (#97)
by carbon on Thu Jul 18, 2002 at 05:46:46 PM EST

I'm glad you found my comment useful. I really can't emphasize enough that I couldn't have done it without the suggestions of the developers in OPN's #C++. In fact, if it weren't for what I've learned in that channel, I wouldn't have found out about any of the above libraries.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Terrific Article! (4.25 / 4) (#40)
by avdi on Thu Jul 18, 2002 at 10:55:58 AM EST

I use boost, ACE, and Doxygen in just about all my code.  They are excellent tools and these days it's hard to imagine coding without them.  

One correction:  In the ACE section you make it sound like ACE has it's own threading system apart from the OS's (I don't know if that's what you meant, but it came out sounding like that).  ACE merely provides generic wrappers for the native threading system, so that multithreaded code can be written once and compiled on nearly any multithreaded OS.  This really works, too - amazingly well.

ACE is a lot more than that though.  One of the great things that has arisen out of the ACE project is a complementary set of low-level to high-level networking and multithreaded programming patterns, documented in the book Pattern Oriented Software Architecture 2: Patterns for Concurrent and Networked Objects.  These patterns are implemented as adaptable templates in the ACE libraries.

--
Now leave us, and take your fish with you. - Faramir

Some other tools (4.60 / 5) (#41)
by avdi on Thu Jul 18, 2002 at 11:05:55 AM EST

Two other tools which I keep near the top of my bag of tricks:

CPPUnit is a XP-style unit-testing toolkit for C++.

SWIG generates API wrappers from C++ code for Guile, Perl, Python, Ruby, Java, PHP, and others.

--
Now leave us, and take your fish with you. - Faramir

SWIG indeed! (4.33 / 3) (#45)
by Ricdude on Thu Jul 18, 2002 at 12:33:22 PM EST

The one-liner mention of swig above does no justice to its utility as an extension generator for multiple scripting languages.  Being able to quickly go from low level class wrangling in c++ to high level plumbing in the scripting language of your choice is a *lifesaver* for certain situations.  Trying to choose between a few scripting languages? Try them all and see which you like the best.

I once had the task of generating a Tcl wrapper for controlling a hardware box with its own c++ interface library (~50 functions).  I had the basic operations wrapped with swig by the end of the day, and most of the more advanced operations (functions with multiple outputs and such) wrapped by the end of the next day.

If it's difficult to wrap your target class's implementation effectively for swig, you can create a wrapper class that manages some of the more hairy details for you.  Then swigify your wrapper class, and go back to worrying about the high level details of your program.


[ Parent ]

OpenC++ (4.00 / 1) (#42)
by threed on Thu Jul 18, 2002 at 12:04:38 PM EST

Compile-time Reflection / Introspection for C++. Good stuff. OpenC++ Home Page

--Threed - Looking out for Numero Uno since 1976!

Ugh! (none / 0) (#113)
by Humuhumunukunukuapuaa on Thu Jul 18, 2002 at 07:38:48 PM EST

While OpenC++ definitely addresses my needs and has its heart in the right place it does so in such a hideous way.  It represents code as strings!  That really does make for some ugly code.  I'd rather use hideous towers of templates to get the same effects because then at least I get various types of static checking and some kind of respect for syntax.  Strings are too crude a medium for representing fragments of code.
--
(&()*&^#@!!&_($&)!&$(*#$(!$&_(!$*&&!$@
[ Parent ]
Hideous Towers of Templates (none / 0) (#155)
by threed on Fri Jul 19, 2002 at 03:23:27 PM EST

I never could get quite the level of self-generation with templates that I can with OpenC++. I have a big array of objects, and a huge hierarchy of objects types that can fill that array. I didn't want to have to rewrite all those ctors and stream operators every time I changed the base class, so I got OpenC++ to do it for me. With templates, the closest I could get was an object that would determine which stream operator to use knowing only the base type - I still had to write the ctors and the streams themselves.

The critical difference is that the OpenC++ version of my base knows what its members are at compile time. I change one and recompile, and it "practically writes itself". How would you approximate that with hideous towers of templates?


--Threed - Looking out for Numero Uno since 1976!

[ Parent ]

What are you writing in OpenC++? (none / 0) (#161)
by Humuhumunukunukuapuaa on Fri Jul 19, 2002 at 09:36:10 PM EST


--
(&()*&^#@!!&_($&)!&$(*#$(!$&_(!$*&&!$@
[ Parent ]
Missed Your Reply (none / 0) (#190)
by threed on Wed Sep 18, 2002 at 04:14:00 PM EST

It's a game, but it has to be extensible as all get out. It may very well never be done.


--Threed - Looking out for Numero Uno since 1976!

[ Parent ]
Why not Guile (3.00 / 4) (#43)
by unknownlamer on Thu Jul 18, 2002 at 12:05:30 PM EST

Why not use GNU Guile Scheme for an extension language? It's the official extension language of the GNU Project (Guile means GNU Ubiquitous Intelligent Language for Extension). It's under a simple GPL plus exception that allows you to link with Guile and not have to become GPLed (although it will be switching to the LGPL because its bignum support is being replaced with libgmp's faster/better bignums). The 1.4 release is old and crusty, but after a lot of work 1.6 is about to be released. After 1.6 some nice stuff like generational garbage collector and a compiler are being worked on (maybe not a full compiler yet, but the evaluator is being cleaned up to get ready for compilation). Guile is a very powerful dialect of Scheme and using it would allow your user to extend your program in a large number of ways. It has nice things like load-extension that allow the Scheme user to load C extensions into their programs, so your application would become almost infinitely extensible. Of course, you can also use safe and clean modules to create modules that have only "safe" bindings (e.g. no load or unlink).

Because Guile is Scheme, anyone can pick it up very quickly. And because Guile is also the official extension language of GNU (all projects that are extensible must eventually use it if they don't already), when you use Guile you add to the unified feel of the GNU system (and since other applications use Guile users that use those will be able to easily extend your program as well). I think the most important part of Guile is that it is actively maintained so you don't have to worry about it suddenly ceasing to exist (in fact, it has been through several sets of maintainers and is still alive).


--
<vladl> I am reading the making of the atomic bong - modern science
I've integrated both Guile and Lua (4.00 / 1) (#46)
by Trevasel on Thu Jul 18, 2002 at 01:11:02 PM EST

And lua is at least 30,000 times easier to integrate. And your run-of-the-mill procedural programmer (or game scripter) will find lua much easier to understand and use.
-- That which does not kill you only makes you stranger - Trevor Goodchild
[ Parent ]
Really? (2.00 / 1) (#55)
by unknownlamer on Thu Jul 18, 2002 at 02:10:52 PM EST

In the old Guile you had to "hack main" to boot Guile, but you don't now (it is still the recommended way because the non-"main hacking" version of the Guile boot searches the stack until it segfaults, which isn't portable)...what is so hard about a few scm_define_gsubr calls and a scm_boot_guile ? Yeah, you have to wrap everything with functions that only take SCM's as args and return types, but you can use swig to do that for you (1.3.12 works great btw). I find Guile easy to use and very powerful (it doesn't take that much effort to learn Scheme either, anyone can pick it up in a few days).


--
<vladl> I am reading the making of the atomic bong - modern science
[ Parent ]
Let me clarify that (none / 0) (#127)
by unknownlamer on Thu Jul 18, 2002 at 10:45:18 PM EST

I looked at the Lua documentation, and it didn't look like it was as nice or easy to use as Guile (the big thing I noticed is that your callback is passed to Lua environment and you have to check that you got the right number of args manually). If you haven't used Guile Scheme in a while, I would suggest that you grab the 1.5.6 tarball and read the (much improved) manual.

I can't really comment too much on Lua, but Guile is very easy to embed in your program. The only thing that you have to do is "hack main" (although you don't have to do that, but I'll discuss that later). Basically you just replace main with a new function named inner_main that takes a void* as its first arg, and then the usual argc and argv. In your main you just put scm_boot_guile (argc, argv, inner_main, NULL);. When inner_main returns, the program stops executing. You can pass whatever data you want as the last arg to scm_boot_guile and it will be passed to inner_main as it's first argument. So now Guile has been booted. Your program can proceed as normal and simply waste the memory taken up by Guile, but that's not what you wanted to do (unless you are really wierd).

So now you have to provide a way for users to actually extend your program with Scheme. The easiest way is probably to just have a scripts dir and load their Scheme from there. So all you have to do is create a scripts dir and load all of the files from that dir using scm_c_primtive_load which takes the filename as it's arg. But the people scripting your program can't do that yet because you haven't given them any hooks into your program. So how do you do that? Just create a set of functions that return a SCM and take all SCM as arguments to wrap your functions. We'll use SCM scheme_foo (SCM req) to wrap int foo (int bar). To register the function for Scheme to use you just call scm_c_define_gsubr (name, required_args, optional_args, rest_arg, function). The names of the arguments should be obvious. If rest_arg is anything other than 0, then the last argument of your function will have the rest of the args passed to the Scheme function (i.e. your function will take an unlimited number of arguments and any non-required or optional arguments will go into the last argument of your function as list). If you have any optional args you have to use SCM_UNBNDP to test if they are unbound. So for this simple example, you'd just scm_c_define_gsubr ("foo", 1, 0, 0, scheme_foo) and now Scheme users can use foo to extend your program in some way.

So what happens if you can't control the main in your program (e.g. you want to make Guile scripting loadable as a plugin to the main program)? Then you use the scm_init_guile which takes no arguments. It basically searches for the bottom of the stack until it segfaults and then saves that position (this is for the garbage collection). This might not run on all platforms, so isn't as portable as scm_boot_guile, but it works.

You might be saying now "but wrapping my functions is too hard!" There are basically two solutions to this: SWIG (1.3.12) and g-wrap. With SWIG you just let it wrap the functions and data types (you may want to provide typemaps to make them nicer to use in Scheme) you want, have SWIG output a C file for you, link the C file and call SWIG_Init in your code somewhere during startup (just put void SWIG_Init () before you use it). You can usually just use your headers almost unmodified (if they aren't filled with tons of preproccesor logic) as the SWIG interface file. G-wrap, on the other hand, actually uses a Scheme file to generate the bindings. I don't have much experience with g-wrap, but it is used in a few project with success.

So basically, embedding Guile isn't all that difficult. It does have a few speed issues, but those are being worked on (e.g. the evaluator is being cleaned out, someone is writing a generational garbage collector, and there are some plans to write a Guile compiler and byte compiler). Guile probably isn't fast enough to be used as a program's primary language (yet), but as an extension language it will mostly be calling procedures that you wrong in C or C++, so the speed of Guile is fine for an extension language. As I mentioned in my original post, Guile is the official extension language of the GNU project, so it would be nice if you embed it in your Free Software (or even you *evil* proprietary software).


--
<vladl> I am reading the making of the atomic bong - modern science
[ Parent ]
Actually (none / 0) (#131)
by carbon on Fri Jul 19, 2002 at 02:12:45 AM EST

Part of what you're talking about is simply due to the fact that Lua is just plain different. I've heard quite a bit about Guile, but I keep getting turned off by it's syntax... I'll eventually get a good Scheme book and learn from that.

As for checking for the right number of arguments, Lua functions either have a specific number of arguments, in which case any calls have their arg count truncated or filled with nils to match, or they use varargs, which just allows you to specify as many arguments as you like. Lua is an easygoing language, and I find that to be nice for scripting, though you might feel differently depending on your designs.

Lua has something very similar to SWIG called tolua, which can automatically generate Lua-compatible callbacks out of C stuff. It's very nice, since it can make some rather good guesses about what you mean and generate Lua code from unsuspecting C (Boo! You are Lua! Muahahaha!).

Also, Lua has support for understanding types beyond it's built-in primtives via tag types, which basically allow you to implement a brand new Lua type externally via C++ code.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Same stuff with Guile (none / 0) (#140)
by unknownlamer on Fri Jul 19, 2002 at 09:53:15 AM EST

Guile has the idea of Smobs, or user defined types (in fact, basically every type in Guile is a smob). Scheme's syntax isn't very difficult at all and can be picked up easily (just use an editor that can match parens and you are all set). Take a look at Teach yourself Scheme in Fixnum Days for a great Scheme tutorial. I don't like the idea of a function call having its arg count filling with nils if the user didn't provide all the required arguments; they are required arguments for a reason.


--
<vladl> I am reading the making of the atomic bong - modern science
[ Parent ]
Not really (none / 0) (#164)
by carbon on Sat Jul 20, 2002 at 01:45:57 AM EST


I don't like the idea of a function call having its arg count filling with nils if the user didn't provide all the required arguments; they are required arguments for a reason.

The idea is for your function to replace nil with some reasonable default value. If there's no reasonable default (and there are surprisingly few cases that I've seen where there isn't one) then just have the function fail the script's execution with an error, or merely have the function have no effect.

This has the additional advantage of being able to simply supply nil as an argument and expecting the function's default behavior; it also allows you to add new arguments to the function without breaking any existing code (well, unless you use varargs, but then your argument count is variable anyways).



Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
C++ is a solid language contrary to popular belief (4.00 / 6) (#47)
by EXTomar on Thu Jul 18, 2002 at 01:12:50 PM EST

This article is great. I am tired of people being extremely negative about C and C++ and claim nothing good can be written in either language. A lot of mind share, tools and libraries like the ones mentioned, and code has been writen around this "evil language". I've used objects both in ACE and Boost. They are very nicely written and more importantly good objects and example of well writen code.

Beyond this it really bothers me when people say "(language binding A) sucks" or "...rocks" or "...better than sliced bread". Each language has their own banes and blessings(ignoring any political/monetary issues). No one language (yet) has solved the universal Comp Sci problem of perfectly expressing the programmer's wishes in all situation(hardware, execution environment etc.). To excell in feature often another must be muddled. No matter how cool you think C# maybe it lacks ease and style Perl excells in(example: find all files that match a variable filename format X through Z, replace text A with B if the filename is X.A or replace text C with D if the filename is X.D). It is possible to write such a task in C# but it is not nearly as elegant as the Perl version would be. In short: given a task pick a language where its feature's strengths are maximized.

Saying this, C and C++ are set apart from other languages, besides their age, by the fact that the syntax is so tied to pointer usage which ties it directly to the execution platform. This is extremely handy in some cases and a pain others. If you want to move image bits from one place to another, changing the red color channel then C/C++ can do this efficiently where other languages would not. This strength is also a weakness since systems represent pointers differently and therefore behavior will be different.

There is nothing in C/C++ that stops other paradyms from being applied. I can't think of an OO construct that can be built in C++. XP style can be applied to code. Streams, pipes and other wacky data types are implementable in C and C++. Features like Garbage Collecting that are lacking in C/C++ have turned out to be not such a "magic bullet". Programmers are still writing mismanaged obfuscated code but in different ways. Debugging code that has poorly constructed try/catch blocks can be as much of a pain as figuring out memory leaks. "Write once/Run everywhere" isn't exactly a magic bullet or as important as people thought.

In short, no language "sucks" outright. Some are just not as good at a given task as others. This is not a reason to harp on it.



ACE (2.33 / 3) (#49)
by onservat on Thu Jul 18, 2002 at 01:21:18 PM EST

Perhaps it's been fixed since, but when I last looked at ACE a couple of years ago, it was unusable owing to its completely amateurish approach to error handling. Avoid.

Evidence? (3.00 / 1) (#52)
by avdi on Thu Jul 18, 2002 at 01:52:18 PM EST

I gave you a 1 because you offer nothing to back up the meaningless statement you made.  Since ACE is used extensively in mission-critical software at dozens of corporations worldwide (including mine), the term "unusable" is simply innaplicable. Care to offer some explanation?

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]
what? (2.00 / 1) (#62)
by pb on Thu Jul 18, 2002 at 03:11:05 PM EST

I gave him a 5 because he shouldn't be punished for offering his personal experience.  Java is also used extensively in mission-critical software at dozens of corporations worldwide; that doesn't mean it's any good.

I believe his explanation was that he tried it a while back, and for whatever reason had some problems with it; that seems reasonable enough to me.  I could say the same thing about the early days of Enlightenment, or Wine.

I have a lot of respect for projects that start out with a solid, usable codebase, but many don't.  I also like it when people stick to an API, instead of making it into an API-moving-target game, as PHP and Java often do in their many different versions and incarnations.

If I gave everybody a 1 because they expressed their personal opinions on this site, there would be a lot of 1's going around, and not many people would be very happy with me, including you.
Now, do you have any evidence besides your opinion that ACE is good/bad, and did you use it a year ago?
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

I do (4.50 / 2) (#71)
by avdi on Thu Jul 18, 2002 at 03:49:24 PM EST

This company has been using ACE successfully for many years.  So that would be my experience with it working.

And no, onservat didn't offer any experience, just un-qualified opinion.  "amateurish approach to error handling" is a meaningless statement, it could just as well mean that the poster didn't know much about C++ when he last looked at ACE.  And the advice to "avoid" was also unfounded, since onservat admitted that s/he hadn't used it in a long time.  

The comment added nothing because neither explained in what way onservat found ACE's error-handling wanting, nor how s/he would define a "professional" error-handling system.  It's like me saying "You should avoid Java, because it's classes suck".  It just doesn't mean anything without some kind of qualification.  I will continue in my practice of downvoting comments which add nothing at all to the conversation.  

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

that's fine... (3.00 / 1) (#81)
by pb on Thu Jul 18, 2002 at 04:33:21 PM EST

You have a right to your opinion; his comment was too short for me to read that much into it, and I appreciate the occasional word of caution.  He admitted that he hadn't used it in a year, which is simply honesty.  And yes, error handling is a black art; I've never liked it very much in general, but it is often quite necessary.

Actually, it would be more like "I used Java a year ago, and it's error handling sucked; YMMV"--and from me, that would be a true statement.  :)

I will continue my practice of voting up comments which have been needlessly downvoted; I like to give people the benefit of the doubt, where applicable.
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

Except... (2.00 / 1) (#110)
by avdi on Thu Jul 18, 2002 at 07:16:38 PM EST

...it wasn't "YMMV", it was "Avoid".  That was the clincher.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]
yeah. (2.00 / 1) (#120)
by pb on Thu Jul 18, 2002 at 08:14:20 PM EST

I agree with you there; I wouldn't say "Avoid" about something I haven't tried in a year, either.
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]
Evidence (4.00 / 1) (#89)
by onservat on Thu Jul 18, 2002 at 05:08:37 PM EST

I gave you a 1 because you offer nothing to back up the meaningless statement you made.
Goodness. A meta-flame. Exciting.
Since ACE is used extensively in mission-critical software at dozens of corporations worldwide
Irrelevant.
  1. I wouldn't do arithmetic the way modern corporations do, and I wouldn't write network programs the way they do, either.
  2. So is FORTRAN. Your point is?
Care to offer some explanation?

As I say, it's a while since I used it, and the codebase is huge, so I'm not going to go digging through it. However, the problem was something like this:

There exists some class which represents a TCP connection to another host/port. It has a constructor which allows you to give the host and port, and ACE will go away and try to connect to it. However, ACE does not use exceptions, so cannot signal the failure of the connection by throwing an exception. Fine, you think, look at the value of errno(3). Unfortunately, the constructor for this class called functions which may themselves set errno; the constructor did not reset errno to zero before returning (IIRC this was something to do with host name resolution). The upshot of this was that it was not possible to tell whether the constructor had succeeded or failed.

Now, perhaps when corporations write mission-critical applications it does not matter to them whether function calls succeed or fail. Sadly, in my application it was vital to know about error conditions.

My other major complaint about ACE is its sheer size. Frankly you're better off calling into the straight BSD sockets API.

(With any luck the ACE people have fixed this problem since I last used it. However, I still can't see much point in the thing.)



[ Parent ]
Eh? (2.00 / 1) (#90)
by carbon on Thu Jul 18, 2002 at 05:17:36 PM EST

Why didn't you just implement a "Hiya Joe!" "Hiya Frank!" checking system and try that? Then you get a lot more control, anyways: not only will the handshake fail if the socket wasn't opened right, but it also fails if the remote peer is going psycho. "Hiya Joe!" "The rabbits are coming! The rabbits are coming! Neehehehehehe!"

Then again, that might not work; I haven't used ACE myself, I put it in as part of a reccomendation and description from quite a few developers in OPN #C++.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
No (2.00 / 1) (#99)
by onservat on Thu Jul 18, 2002 at 05:48:19 PM EST

Two reasons--
  1. What about a protocol where the server sends the first data? With error handling this crummy, you might find yourself waiting for ever.
  2. Why use a big complicated library which gets it wrong when you may as well use a small (relatively) elegant interface which gets it right?
ACE wraps the system call interface, but it hides its error handling without replacing it with anything useful of its own.

[ Parent ]
Eh? (4.00 / 1) (#119)
by carbon on Thu Jul 18, 2002 at 08:07:34 PM EST

1. What about a protocol where the server sends the first data? With error handling this crummy, you might find yourself waiting for ever.

Nah, this wouldn't be data, and it doesn't even matter which side sends first. One side or the other has to 'initiate' the connection, and whether it's the server or client or even one of two peers, just have that side throw out a known magic number first and expect the reply before starting on with your real transmissions.

2. Why use a big complicated library which gets it wrong when you may as well use a small (relatively) elegant interface which gets it right?

Are you absolutely positive that ACE is like this currently? You said it's been a while since you've worked with it.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Eh. (none / 0) (#158)
by onservat on Fri Jul 19, 2002 at 05:16:39 PM EST

1. What about a protocol where the server sends the first data? With error handling this crummy, you might find yourself waiting for ever.
Nah, this wouldn't be data,
If it's sent and it isn't data, what is it?
just have that side throw out a known magic number first and expect the reply before starting on with your real transmissions.

It is not clear to me whether you are deliberately misunderstanding me or not.

I am going to assume that you know that there exist in the real world protocols where the client sends data first (e.g., HTTP) and protocols where the server sends data first (e.g., SSH).

You cannot change the protocol. You must implement it as it is defined. Typically it is helpful to choose an approach to the problem which makes it easy to implement it. Using a library in which the absence of sensible error reporting makes it impossible to do this is a poor design choice.

Are you absolutely positive that ACE is like this currently? You said it's been a while since you've worked with it.

No, and I have neither the time nor the inclination to find out whether it has changed. Perhaps it has.

Equally, perhaps it hasn't. Do you want to check all 16Mb of code? I don't.

Reusable code is a great idea. But when it takes you as long to check whether a library is sensibly implemented as it would to implement the functionality you want without using the library, you know that using the library is not the correct choice. In my experience, ACE is not the correct choice.



[ Parent ]
Responses (none / 0) (#163)
by carbon on Sat Jul 20, 2002 at 01:39:57 AM EST

If it's sent and it isn't data, what is it?

For example, take a look at PPP's LCP: it doesn't send any data, as such, but merely allows sending control, status, and other meta-information.

I suppose that's data as well, but that's just a semantic distinction.

You cannot change the protocol. (Metions of SSH, HTTP)

Well, if you're implementing a known protocol, that's different. I was under the impression that you were creating your own client/server protocol, but in retrospect that wasn't a safe assumption. Sorry about that...

Equally, perhaps it hasn't. Do you want to check all 16Mb of code? I don't.

Who says you have to check every single line of code? That would be silly. Just check the documentation and scan for error handling and exceptions.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Why must I choose a new subject for each comment? (none / 0) (#179)
by onservat on Mon Jul 22, 2002 at 09:44:19 AM EST

For example, take a look at PPP's LCP: it doesn't send any data, as such, but merely allows sending control, status, and other meta-information.

I suppose that's data as well, but that's just a semantic distinction.

I suppose I shouldn't be surprised that you brought up the ISO layer cake in another post....

It's pretty obvious in this context that `data' means `stuff transmitted over the network'.

Who says you have to check every single line of code? That would be silly. Just check the documentation and scan for error handling and exceptions.
I see that ACE now has a whole load of documentation, which I don't recall from my previous encounter with it. It might help, or it might just add to the volume of stuff to check. Who knows...?

[ Parent ]
responses (5.00 / 2) (#114)
by avdi on Thu Jul 18, 2002 at 07:39:56 PM EST


2. So is FORTRAN. Your point is?

That it's clearly not "unusable".  Thank you for making my point.

it was not possible to tell whether the constructor had succeeded or failed.

If it's important to you to know this (and it's by no means important in all applications; in some it might be acceptable to find out only after the first attempt to send), then you simply use the 'connect()'  method rather than connecting during construction.  connect() returns a perfectly straightforward, reliable success/failure value.

AFAIK, this isn't anything new.  It's a stable part of the one the oldest sections of the API, leading me to believe this was a simply a failure to RTFM.

BTW, there's a reason for the lack of exception support.  For one thing, ACE got started long before exceptions were standard on all C++ compilers, and it retains the ability to be compiled on an amzing variety of crappy compilers.    For another, in a lot of embedded code exception support is deliberately turned off, for a variety of reasons.  Anyway, it's easy to fit ACE into a nice modern exception-throwing error-handling architecture; I do it with a simple bouncer-function which I wrap ACE calls in.  If the ACE call returns an error, the bouncer throws the appropriate exception.


My other major complaint about ACE is its sheer size. Frankly you're better off calling into the straight BSD sockets API.

You've missed the point.  If you have no need of the higher-level pattern abstractions, AND you have no need for extensive portability, why would you even consider using ACE?  If you don't have those constraints you're better off just using the BSD calls. Our code has to be cross-platform, and we save gobs of work with the pattern templates like Acceptor-Connecter, Reactor, etc.

If you had just said "it wasn't useful in my project", I wouldn't have downvoted you.  But you chose to call it "unusable", and advised the readers to "avoid" it.  This is was unqualified disinformation, and that's why I responded the way I did.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

sesnopser (none / 0) (#159)
by onservat on Fri Jul 19, 2002 at 05:28:12 PM EST

2. So is FORTRAN. Your point is?
That it's clearly not "unusable". Thank you for making my point.

Please tell me that you aren't implementing new code in FORTRAN.

Re. your comments about reading `the fucking manual'. I did; it was useless. So I read the code. That's how I established the pathology of its behaviour.

As for your comments about exception support... well, I recently saw a mail autoresponder written in FORTRAN. It's like dogs that paint: it's not how well they do it, it's that they do it at all. The same technological point applies to C++ without exceptions.

You've missed the point. If you have no need of the higher-level pattern abstractions, AND you have no need for extensive portability, why would you even consider using ACE? If you don't have those constraints you're better off just using the BSD calls. Our code has to be cross-platform, and we save gobs of work with the pattern templates like Acceptor-Connecter, Reactor, etc.

Ah yes. But my understanding of ACE is that the higher-level constructs are built on top of the low-level constructs. I have explained why I do not trust the low-level constructs. I would not use the high-level constructs because of the potential for problems in the low-level constructs.

(I will repeat again that it is a couple of years since I have used ACE. Perhaps this stuff has been fixed. I do not know, and I do not intend to check, because I believe that it would take me longer to verify my understanding of the code than to implement my own version of whatever subset was required with certainty about the error handling and other vital details of the implementation.)



[ Parent ]
uhh... (none / 0) (#165)
by avdi on Sat Jul 20, 2002 at 06:03:29 PM EST

Do you make a career out of missing the point?  I've tried to be civil, but this is getting absurd.


Please tell me that you aren't implementing new code in FORTRAN.

You stated ACE was "unusable".  I proved that statement wrong by giving evidence of extensive successful use.  Now you're on a FORTRAN tangent. What gives?  Just admit it: ACE is usable. People use it.  You may think that they are deludedly using an unusable product, but from the perspective of one who does use it, and who is surrounded by people who have been using it for years, I know you are wrong about that.

Regarding TFM:  Yes, back then the code may well have been TFM.  That's what you have to deal with in the earlier versions of any system.  It's the price of being an early-adopter.

The rest of your message details how the low-level problems in ACE make the high-level constructs untrustworthy.  I already addressed your problems with the low-level constructs:  you were WRONG.  There is and was a way to reliably determine whether a connection has succeeded: it's the connect() method.  I also pointed out how easy it is to fit this into an exception-using system.  It's not a kludge; it's exactly what you would have to do to get the BSD calls to be exception-friendly. Actually, it has more exception support because using an ACE connection class at least garauntees that the appropriate resources will be freed if an exception is triggered somewhere; something you're not going to get with BSD calls.  

Your last post was just an elaborate way of avoiding the fact that you completely missed the connect() method in your reading of the ACE manuals and code when you last used it.  That method addressed your problems, with every bit as much exception-support as the BSD calls you tout as a superior solution.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

fish soup (none / 0) (#173)
by onservat on Sun Jul 21, 2002 at 07:06:57 PM EST

Only one bit of this rant worth responding to:
I already addressed your problems with the low-level constructs: you were WRONG. There is and was a way to reliably determine whether a connection has succeeded: it's the connect() method.
This still doesn't help me detect errors in the constructor for the class. It also suggests to me that the authors don't understand error handling.

[ Parent ]
Yes, it does (none / 0) (#174)
by carbon on Sun Jul 21, 2002 at 08:49:30 PM EST

The point is, whatever function is closest to connect() can then check it for the error condition and throw an exception if it occurs. The whole object tree doesn't have to This is called multi-layer abstraction: as you go higher up the tree (in this case, an object/call tree, not a class tree), you have less and less low-level data and more and more complex structures. This sort of thing has been applied very well to networking models (heard of the 7 layers?)


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Hmm. (none / 0) (#178)
by onservat on Mon Jul 22, 2002 at 09:39:45 AM EST

You obviously believe that it's OK to write code which doesn't allow its caller to detect errors. I do not.

[ Parent ]
oh yeah? (none / 0) (#180)
by avdi on Mon Jul 22, 2002 at 12:54:46 PM EST

You obviously enjoy torturing small animals.

The previous statement bore exactly as much relation to your last post as your last post did to carbon's.  

I take it your debate philosphy is: "When proven wrong, pull an ad-hominem attack out of thin air".  I now regret spending so much time responding to a troll.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

oh sod it, how's this for a subject? (none / 0) (#181)
by onservat on Mon Jul 22, 2002 at 04:06:07 PM EST

When proven wrong, pull an ad-hominem attack out of thin air
... and it looks as if you don't know what `ad hominem' means, either. I give up.

[ Parent ]
Thank you. (none / 0) (#175)
by avdi on Sun Jul 21, 2002 at 10:50:27 PM EST

Thank you for conceding the "unusability" point.

As for constructors:  if you'd bother reading what I have to say instead of just talking out of your ass, you would realize how silly that was.  If you connect explicitly, the constructor essentially does nothing.  There are no errors to detect.  How many times do I have to explain this before you get it?  Let's go over it one more time, in excrutiating detail:

The authors understood error-handling perfectly well. They also understood their requirements: useful middleware that could be used in the all-too-common systems in which Exceptions are verbotten, either for reasons of inadequate compilers, code size, execution speed,  or interfacing with legacy, non-exception-safe code.  Thus they provided a safe, explicit way of establishing connections which could be checked unambigously for errors.  It's called connect().  There's no need to check the constructor for errors in this case.  Do I need to lay things out any more simply for you?

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

hmmm (none / 0) (#177)
by onservat on Mon Jul 22, 2002 at 09:38:51 AM EST

I don't agree with you. I shall not be using the library again, in any case.

[ Parent ]
Agreed, ACE is crap (2.00 / 1) (#67)
by czth on Thu Jul 18, 2002 at 03:37:37 PM EST

Last I tried to use ACE (end of last year), it was a steaming pile of poo. Any library that tries evil things like #define main ... deserves to be rm -rf'd as soon as possible. Also, their evil ostream libraries conflicted horribly with the C++ ones (or maybe I'm thinking of Rogue Wave, which is also a steaming pile); whatever it was, it didn't play nice with other libraries or the STL. ACE is riddled with macros, grossly bloated, and the source is extremely ugly. We were looking at it for CORBA, and (before I left) the company was looking at going with Orbacus, which is the complete opposite in all respects: clean code, easy to use, good docs etc. Orbacus does charge for commercial use, though, but whatever they charge, it's better than struggling with ACE (shudder).

czth

[ Parent ]

Word of warning (4.00 / 1) (#50)
by ucblockhead on Thu Jul 18, 2002 at 01:22:11 PM EST

The boost library is generally good, but the regular expression library is very slow. Don't attempt to use it (as I did) in a performance critical part of a program.
-----------------------
This is k5. We're all tools - duxup
hmm... (4.00 / 1) (#51)
by pb on Thu Jul 18, 2002 at 01:44:22 PM EST

In that case, do you have any suggestions?  PCRE?

I wrote a simple HTML parser in PHP that uses regexps to do its parsing, and I've been toying with the idea of porting it to C++.  The data structure should be pretty easy to port (in C++ I guess it'll be a(n optionally nested) vector of tokens), but I'd still like to use regexps in the parsing, because it simplifies things immensely.
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

Unfortunately, no... (5.00 / 1) (#53)
by ucblockhead on Thu Jul 18, 2002 at 02:00:39 PM EST

Depending on what you are doing, it may not be an issue. The case I had was parsing lines like:

#EXTRAT 10
#EXTFIL c:\Foo\bar\baz.mp3
I wrote a simple expression to pull it out, something like: ^\w*#EXT(RAT|FIL)\w*([^\w]*)\w*$

Perl was able to run through the (fairly large) file about ten times faster than C++. Since the regular expression was relatively simple, I just did it the old way. I was distinctly unimpressed because it should have been pretty trivial to parse these things given that 99% of the time, there was no whitespace at the beginning and the ending of the strings.

I wish I had a suggestion...I still use boost, just not as often as I'd like. I don't use it like Perl regexes, where I through nearly everything at them.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

10 times slower is no big deal (none / 0) (#54)
by Levi on Thu Jul 18, 2002 at 02:03:44 PM EST

I can't see how it would make a bit of difference?!

[ Parent ]
hmm... (5.00 / 2) (#56)
by X3nocide on Thu Jul 18, 2002 at 02:32:10 PM EST

Since I can't decide whether you're joking or not, I'll simply have to assume the worst. Sure, given a single request, 10 times slower may not seem like such a big deal and all. So the program runs an extra 30 milliseconds or something. But where this does come into play is when the code you're writing will be used by many people at once, like a webserver or database. Then all of a sudden 30 milliseconds of work turns into 30 seconds of work. Now 30 seconds is pretty large just for one part of the operation, but 3 is a little bit less extreme. So your choice is to spend more money or more hardware, or rewrite the software to run faster.

Sometimes it seems like more and more companies are choosing faster hardware over more efficient software; this is probably why I should switch from CS major to Computer Engineering. :(

pwnguin.net
[ Parent ]

Yes indeedy (none / 0) (#66)
by ucblockhead on Thu Jul 18, 2002 at 03:34:06 PM EST

Yeah, if it is one call, it's no big deal, which is why I still use boost for many things. But in the example above, I was using it on every line in a fairly large file. Instead of loading the file in a few seconds, it took nearly a minute to load. Annoying.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
ok... (none / 0) (#58)
by pb on Thu Jul 18, 2002 at 02:41:42 PM EST

I guess I'll try PCRE, then, and maybe Boost, depending on the calls they support.  I'm exclusively using preg_split in the PHP code, to parse out the various different types of tokens from the page; it might not be the fastest approach, but it's very easy and simple to do, and is likely a lot less code than doing the tokenizing by hand...

A factor of 10 is often the speed difference between a compiled and an interpreted language; in this situation, it sounds like Boost regexps are going 10-100x slower than they should be, were they written correctly!  (and yes, people, a factor of ten is a huge deal; an hour and forty minutes is intolerable, whereas ten minutes is simply annoying...)
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

obligatory "you misrepresented java" pos (3.80 / 5) (#59)
by zzzeek on Thu Jul 18, 2002 at 02:43:42 PM EST

C++ has a lot of practical language features, such as templates, functors, operator overloading, pointers, and multiple inheritance. Java, for example, does not implement any of the above things in its current incarnation.
Since the Java language operates off of different development paradigms than C++, the functionality granted by the above features is often provided in a different way. I don't often hear of Java programmers complaining that the language is in need of these features (with the possible exception of templates). I think usually someone transitioning from the C++ paradigm to the Java paradigm would miss those features until he/she learns more about the ideologies and techniques that go into Java application design.

Templates are less necessary (though some people still desire them) since every object in Java derives from the base class Object and any kind of library, such as the standard collection classes, can deal with passing every kind of object (and native types wrapped in objects, to the chagrin of some) based on the Object superclass. The main argument for templates is that there is a slight performance hit associated with all the casting this introduces. Java likes to choose simplicity over small performance increases, quite often (*shrug*).

Saying Java doesnt have "pointers", at least to me, implies that you are unable to refer to objects by reference, which isnt true; it would imply that you can't even build basic data structures in Java. Everything in Java, other than the native types, are referred to by reference, so nearly everything is a "pointer". You can't do pointer arithmetic, since its against the spirit that Java was created in (i.e., despite the neat performance and bloat-reducing tricks you can do, its a huge source of confusing and/or broken code).

Multiple inheritance is not present in the way it is in C++, i.e. a class can not derive itself from more than one superclass, but it does support multiple interface implementation, which is an essential technique in Java. Many programmers would argue that this is the only kind of multiple inheritance that you really need, as anything more elaborate (actually having code and method implementations behind those inherited interfaces) becomes confusing and unworkable.

My impression of operator overloading is that it finds a lot of usage in things like writing objects that do reference counting for garbage collection purposes. Since Java VM's do garbage collection automatically, this is probably why its not a very important language feature in Java.

But functors, well im not a C++ guy so I will humbly admit that I don't even know what that is. :)



You have a point (4.00 / 1) (#61)
by carbon on Thu Jul 18, 2002 at 03:00:15 PM EST

My main issue is that different design paradigms, as you say, often translate into different applicabilities.

However, I have noticed that Java does come close to implementing several of those features without actually doing it.

The main reason I like templates is that it enforces type safety, and it's useful for more then containers. Although every object derives from Object (this is just a standard object-root heirarchy, as with Smalltalk) you usually want a container with at least some guaranteed capabilities.

Although Java does have references, they aren't quite the same thing. From what I've seen of Java, you're forced to use heap references (i.e. operator new) to refer to any class objects, whereas in C++ you can create a class object just like a primitive. This is also what operator overloading is for: to make a class act like a primitive. Java actually implemented some of operator overloading for the String class, for example to add two strings together. And it seems to act as though it would really like it in some places, such as with the Comparable interface, which acts rather like the comparison operators.

I do agree that C++'s multiple inheretences isn't particularly useful for combining implemetnations. Usually the most common thing in C++ is to have a semi-interface with default implementations that the base class can override selectively. Thus, it really is partially implemented...
And the n

Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
yah i guess i have different habits as a result (4.50 / 2) (#64)
by zzzeek on Thu Jul 18, 2002 at 03:24:55 PM EST


The main reason I like templates is that it enforces type safety, and it's useful for more then containers. Although every object derives from Object (this is just a standard object-root heirarchy, as with Smalltalk) you usually want a container with at least some guaranteed capabilities.

Yeah, I didn't even think of this one off the top of my head, because the reason this doesn't come up for me too often is that I have a naturally habitual technique of never passing those various generic "container" classes between objects. I.e. if I'm using List or Map I will tend to keep it privately within one object, so its pretty easy to guarantee that it only has the proper types inside it.  

When I work with other programmers and I see them passing a List from one object to another, and they say "well its a List of Foo", I'll say either to use something like Foo[] (i.e. a native array), or to create another class or method that abstracts away the fact that you are using Map or a generic Tree or whatever, and also represents the data and operations you are working with very specifically.  So in one sense, you could say I am going through all this extra effort to make wrappers for generic data structures, but in the other sense you could say that I would never want represent complicated method parameters so generically anyway.

Another reason people probably dont ask for templates all the time is that we are softened by the presence of the VM, where our class cast problems come out as a nice little stack trace instead of the whole machine freezing up :).

[ Parent ]

templates (none / 0) (#74)
by ucblockhead on Thu Jul 18, 2002 at 03:52:51 PM EST

The nice thing about the type safety of template collections is that you find out at compile time that you've got a bug, not at runtime.

And it is very hard to make C++ code that freezes the whole machine these days.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

templates (none / 0) (#82)
by zzzeek on Thu Jul 18, 2002 at 04:36:00 PM EST

The nice thing about the type safety of template collections is that you find out at compile time that you've got a bug, not at runtime.

Thats why I advocate passing data structures that are relatively non-generic between different classes (and hide the usage of a more generic set of classes), so the big inter-class type safety issues are found at compile time.  I'll grant that I'm possibly busting my ass for nothing and missing out on a great feature, though.  My point was only that when I played with C++ the need for templates was very obvious, whereas in Java it didnt seem to be quite as urgently required.  The practice of creating non-generic data structures for specific situations seems much cleaner to me as well.  But templates are a frequently requested feature in Java.


And it is very hard to make C++ code that freezes the whole machine these days.

Yes yes just a jest....I did a good deal of cross platform C years ago and it was either core dump, seg fault, or MS Dev Studio popping up a debugger.


[ Parent ]

Well... (none / 0) (#104)
by ucblockhead on Thu Jul 18, 2002 at 06:16:35 PM EST

Again, having used templates in C++, going to a language like C# that does not have them is painful. In most cases, it isn't really about data structures as it is about code generation. As others have said, templates are souped-up macros. They are great for situations where you have code that you find repeated over and over, but for which things like inheritance doesn't help.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
Let's hear it for souped-up macros... (none / 0) (#123)
by pb on Thu Jul 18, 2002 at 09:15:51 PM EST

Before there were templates, you might have had to change a typedef or a #define, and possibly copy some code, but that's about it.  With templates, the compiler does (most of) that for you.  In my mind, it's more of a convenience issue than anything else.  I'm sure I don't need to tell you all this, but it's still handy stuff for when you don't have templates.

The Trivially Simple Example:

#define add(a, b) (a + b)
This inlines the code for the add function; not always what you might want to do, but good for short stuff.
The More-Template-Like Example:

#define gen_add(t) t add_##t(t a, t b) { return a + b; }

This is much more similar to how templates actually work; gen_add generates the appropriate function for the type given.  Therefore, gen_add(int) produces the code for the add_int function, which adds two integers.  The stringification for the function name is unnecessary in C++ thanks to function overloading, which makes this much more template-like.

That was just off the top of my head; I know people have done many things like this and worse, to get the same sort of functionality that templates provide in C++.  That's another thing I don't like about Java--not only does it not have templates, it doesn't have a preprocessor either!
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

preprocessor (none / 0) (#124)
by zzzeek on Thu Jul 18, 2002 at 10:00:11 PM EST

I have sometimes lamented about the lack of a preprocessor as well.  The reasons I vaguely recall reading from the Gosling gang et al, were that, since Java is cross platform, you wouldnt want to have a preprocessor, since they are used primarily for different "build configurations" and this concept does not apply to Java classes....the VM takes care of platform considerations.

*steps back to avoid the flames*

[ Parent ]

yup... (none / 0) (#126)
by pb on Thu Jul 18, 2002 at 10:36:18 PM EST

That's the problem with Java, that word "primarily".  The idea is that there's a feature that 99% of the people out there don't use properly, and therefore the feature is bad, and shouldn't be in Java.  Never mind that it completely screws over the other 1% who know why the feature is there, what it's for, and when to use it...

Since people already mentioned the lack of MI and templates in Java, another great example of this Java arrogance is "goto"; the developers didn't just leave it out of the language--they made it an unimplemented keyword!
I think I'll call it the "Java knows best" philosophy...
---
"See what the drooling, ravening, flesh-eating hordes^W^W^W^WKuro5hin.org readers have to say."
-- pwhysall
[ Parent ]

No, trust me... (none / 0) (#185)
by spiralx on Wed Jul 24, 2002 at 02:47:26 PM EST

... a preprocessor would be marvellous for me right now. I have code as part of an applet, and I want to use the same code as part of a servlet. Unfortunately it's a fucking nightmare, whereas in C I could just use a few #ifdef APPLET commands and build both versions from the same codebase.

You're doomed, I'm doomed, we're all doomed for ice cream. - Bob Aboey
[ Parent ]

Heh (none / 0) (#80)
by carbon on Thu Jul 18, 2002 at 04:26:49 PM EST

By guaranteed safety, I meant safety of the object contained within the template. For example, a template might need dereferencing and incrementing for it's contained object. Although templates can't specify a base class, the compiler will check to see that anything you try and pass to the template is sane for what the template tries to do. This is also why operator overloading is handy, as it allows you to put primitive types into templates as well as classes you define to act like primitives (such as your own pointer class, or your own integer-ish class). Operators just define a set of standard methods that a lot of classes implement, under standard names that are also shared with primitives, and with a different method call syntax.

With Object used within containers, you not only cannot pass primitives to a container without altering it (that's what Integer is for, but it's rather klunky) but you also cannot build generic containers and maintain type safety. When I pop an Object stack, I get an Object back, which I can't do anything with. I have to make a downcast, which is only safe if I have complete control over the container. Because of that, I really cannot safely build methods that accept containers as arguments.

You do have a point that that may merely be a C++ method, and that I might be better off making a simple little wrapper class. But then again, the STL can do this too: if I create a class derived from list or map, I get that container-ness while being able to restrict access as I please, including automatic polymorphism. For example, I regularly make tiny public children of STL's string, so that I can identify sub-types of string individually, and later add individual behaviors to these types of strings without altering the external interface.


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
yup yup (none / 0) (#87)
by zzzeek on Thu Jul 18, 2002 at 04:52:21 PM EST

Points taken with regards to operator overloading.  I think Java is just trying to limit how many syntactical tricks you can pull off to increase maintainability and clarity.  

Sometimes I even think that the built in String operators that you pointed out shouldnt be there, since it might be better for programmers to understand what is really going on and be forced to use StringBuffer.append(), etc.

The native wrapper classes such as Integer, admittedly clunky.  

But this is highlighting a big paradigm difference between Java and C++:  if you look at any of the big time Java API's out there, they usually dont pass around Lists and Maps in their method declarations to and from the outside world (though they will pass around simpler classes like Iterators which are not very mutable).  Its much more common that everything has its own type-specific container (as another member of the package or a related package) to pass around.


[ Parent ]

Multiple Inheritance (4.25 / 4) (#63)
by NFW on Thu Jul 18, 2002 at 03:11:19 PM EST

Multiple inheritance is not present in the way it is in C++, i.e. a class can not derive itself from more than one superclass, but it does support multiple interface implementation, which is an essential technique in Java. Many programmers would argue that this is the only kind of multiple inheritance that you really need, as anything more elaborate (actually having code and method implementations behind those inherited interfaces) becomes confusing and unworkable.

Other programmers (myself included) argue that multiple inheritance of implementation (not just interface) allows for some spectacularly useful and resuable code.

It's true that there are confusing and difficult-to-maintain things that you can do with MI, and IMO the worst offenders could be (and should be (and often are)) treated as compiler errors, or at least warnings.

But when you have 'helper' classes that don't overlap, and that provide useful functionality, why not add them to the base class list and be done with it?


--
Got birds?


[ Parent ]

admittedly controversial (none / 0) (#65)
by zzzeek on Thu Jul 18, 2002 at 03:27:03 PM EST


But when you have 'helper' classes that don't overlap, and that provide useful functionality, why not add them to the base class list and be done with it?

Lots of folks would say if you have "helper" classes then you should be using Composition instead of inheritance.  Someone just put up a k5 article about this the other day.

[ Parent ]

different tools for different problems (1.00 / 1) (#83)
by NFW on Thu Jul 18, 2002 at 04:41:09 PM EST

Composition is the right tool for some jobs, MI is the right tool for others. MI in C++ can extend a class' interface and its implementation. Java's brand of MI extends an object's interface, but not its implementation. Composition extends an object's implementation, but not its interface.

They each have their place, but composition is the wrong tool for the job if you want to give a class new functionality and a public interface with which to access that functionality. It gives you the functionality, but if you want a public interface to it you're stuck writing code by hand to delegate from the interface to the implementation. MI in the style of C++ gives you that for free.


--
Got birds?


[ Parent ]

"is a" (none / 0) (#88)
by zzzeek on Thu Jul 18, 2002 at 05:00:54 PM EST

Inheritance should only be used to specify an "is a" relationship between two classes.  If you are talking about helper objects, like utility classes and whatnot, your subclasses, which may represent application specific implementations and processes, do not represent the same concept as that of your utility classes, and therefore should not subclass them, meaning they should refer to their needed helpers, but not become instances of them.  

I think the idea in Java was that a true "is a" relationship, including the fact that "this object A 'IS A' B's implementation and also 'IS A' C's implementation", is rare, and MI is too easily used to bundle methods from unrelated objects into one class.  As is the theme in all of these examples, they limit the syntax of Java where those syntaxes all too often are extremely easy to lead towards poor design.

[ Parent ]

is-a with helper classes (1.00 / 1) (#93)
by NFW on Thu Jul 18, 2002 at 05:25:57 PM EST

Inheritance should only be used to specify an "is a" relationship between two classes. If you are talking about helper objects, like utility classes and whatnot, your subclasses, which may represent application specific implementations and processes, do not represent the same concept as that of your utility classes, and therefore should not subclass them, meaning they should refer to their needed helpers, but not become instances of them.

If you need to reuse the interface of a helper class, and you need to reuse the implementation of a helper class, public MI is the right tool for the job. You could use containment, but then you have to write delegation code by hand (that's a waste of time when you could just publicly inherit), and you have to update all of the delegation code by hand if the helper class interface changes (more time wasted).

An example from the project linked in my signature... The simulator has a class called "Component," which is the base class for the joints and bodies in the simulation. An objects of class Component "is a" serializable object, so Component derives from a widely-used base class called Serializable. It "is a" sender of events, so it derives from a widely-used Notifier helper class. It "is a" observer of events from other components, so it derives from derives from a widely-used Observer helper class. A Component "is a" selectable object (in the sense than you can select them in the UI), so it derives from a widely-used Selectable helper class.

This could all have been done through containment, but then I'd be stuck writing delegation code by hand for a couple methods in Serializable, a few methods in Selectable, and a few methods in the Notifier and Observer classes. That would be wasted time. Then, every time the aforementioned helper classes had a method change signature, I'd be rewriting delgation code in a boatload of derived classes. That would be a huge waste of time.

Components also have names, positions, orientations, etc, so they use composition for the string and vector classes as necessary. Different problems, different tools to solve them.


--
Got birds?


[ Parent ]

Meyer's Object Oriented Software Construction (none / 0) (#167)
by russ on Sun Jul 21, 2002 at 12:58:06 AM EST

Check out Bertrand Meyer's Object Oriented Software Construction for some pretty cogent arguments supporting multiple inheritance as a good and useful thing. Personally I find it very useful.

[ Parent ]
Not impressed. (none / 0) (#169)
by i on Sun Jul 21, 2002 at 01:49:04 AM EST

Eiffel is way older that C++, and still can't get its multiple inheritance just right.

and we have a contradicton according to our assumptions and the factor theorem

[ Parent ]
You're funny (4.00 / 2) (#68)
by avdi on Thu Jul 18, 2002 at 03:39:10 PM EST


Templates are less necessary...The main argument for templates is that there is a slight performance hit associated with all the casting this introduces.

Tee hee. Heh.

My impression of operator overloading is that it finds a lot of usage in things like writing objects that do reference counting for garbage collection purposes.

Eh heh! Eh hah hah! Heh hehe hoo haha ho hah! ::snort:: ::wheeze:: ::giggle::

You make me laugh.  My recommendation: don't talk about the advantages/disadvantages of Java vs. C++ unlesss you are a "C++ guy" as well as a "Java guy".  Hint:  Templates are about static-typing, not about polymorphism or efficiency.  C++ is a staticly-typed language.  Python is a dynamicly-typed language.  Java can't decide which it wants to be and manages to fall into the deep stinky pit in between.

Which is not to say that I dislike Java.  But don't talk about why Java doesn't need certain C++ features if you're so unfamiliar with C++ that you have no idea of the actual reasons for those features.

And no, Java doesn't have functors, but it manages to awkwardly make up for that fact using anonymous inner classes.

--
Now leave us, and take your fish with you. - Faramir
[ Parent ]

i knew someone would say this (3.00 / 1) (#77)
by zzzeek on Thu Jul 18, 2002 at 04:17:06 PM EST

But don't talk about why Java doesn't need certain C++ features if you're so unfamiliar with C++ that you have no idea of the actual reasons for those features.

Thanks for the juvenile flame.

Like I said, Java developers (including those who are C++ experts as well) have done just fine without them, whether or not we are expert at their usage. I am aware of some of their uses, and why they are not needed in Java quite so much, so why cant I say "we don't need them so badly?" I have seen lots of C++ programmers convert their C++ programs line-for-line to the best Java equivalent and then declare "Java sucks" because it doesnt look clean or perform well; this is an unfair comparison, and I am merely pointing that out. Its a different language, different paradigm. I can freely point out that Java is a reasonably complete language without much need for new features, even if I had no C++ or C experience at all (and I have done a good amount of C).

My admission over not being a C++ expert was in the spirit of honesty and provoking reasonable discussion, I am sorry you weren't able to pick up on that and used it against me instead.



[ Parent ]
JSR-014 (none / 0) (#182)
by joeD on Tue Jul 23, 2002 at 05:32:42 PM EST

safe generic programming is #1 on the list of most requested RFEs in Java. so, while it's true that Java developers have managed without them, there appears to be a sizable population who think they're worthwhile enough to add to the language.

[ Parent ]
Templates and performance (4.66 / 3) (#72)
by ucblockhead on Thu Jul 18, 2002 at 03:49:43 PM EST

From what I can tell, that performance hit is a factor of three or so. It is certainly not trivial. The thing you have to remember about the template containers is that the were designed specifically because of the shortcomings of various container libraries that used the "everything derives from object" model. Of course, some of those shortcomings had to do with the C++ lack of a base object, but not all of them.

Anyway, there's lots of things you can do with templates besides designing particular containers. After working with templates for years, going to a language without them (C# in my case) is like coding with one arm tied behind my back. So, so often I end up writing the third copy of nearly repeated code and think to myself "if only I could just make this a template".
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

Template containers are THAT slower? (none / 0) (#75)
by Skywise on Thu Jul 18, 2002 at 03:56:23 PM EST

I could see that for stuff like vectors (where the [] operator requires a complete re-calc of the data position), but I would think the list containers aren't that bad off...

Definitely your program will be larger than the "everythings an object" model, if you use many different data types though.

[ Parent ]

Yup (none / 0) (#76)
by ucblockhead on Thu Jul 18, 2002 at 04:08:02 PM EST

I wrote a story on it recently...the containers are indeed that much slower.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]
Surely it's the other way round? (none / 0) (#136)
by Homburg on Fri Jul 19, 2002 at 06:26:54 AM EST

Vector has constant time operator[]. It's insertion and removal that are slow for vectors (whereas they are constant time for lists).

Anyway, this is a function of the data structure used, and has nothing to do with whether they are templates or not.

[ Parent ]

Maybe. (none / 0) (#147)
by Skywise on Fri Jul 19, 2002 at 11:36:38 AM EST

Right [] is constant, but you can iterate faster using pointers...

If you use an array instead of a vector, you can assign a pointer to walk up and down the array.  If you have to iterate over the entire array sequentially, you can just do:

char fred[50] = "blah";
char* char_ptr = fred;

int i;
for(i = 0; i < 50; ++i)
{
     char a_char = *char_ptr;
     char_ptr++;
}

With a vector, you can setup an iterator loop, but then you're double indirecting *(iterator->char_ptr).  (Although I suppose that could all be inlined and optimized away...)


[ Parent ]

Should be optimized away, at least in theory (none / 0) (#151)
by Homburg on Fri Jul 19, 2002 at 01:04:42 PM EST

Surely you'ld only get double indirection if you used a vector of char* (which would be an odd thing to do)?

On a number of implementations, vector<T>::iterator is just a typedef for T*, so using vectors and iterators ought to be just as fast as using arrays and pointers. On those implementations where this isn't true, it should be possible in principle to inline and optimize, as you say, although that may not happen on all implementations.

In general, I don't think there's any reason why using a generic version of a data structure should be slower than hard coding in the type.

[ Parent ]

That's what I would think... (none / 0) (#154)
by Skywise on Fri Jul 19, 2002 at 02:13:41 PM EST

My original statement was based on end-of-day off the cuff thinking that all vector access would be through the [] operator too...


[ Parent ]
templates (5.00 / 1) (#86)
by jacob on Thu Jul 18, 2002 at 04:51:37 PM EST

The more I hear C++ people talk about how they use templates, the more I think they're in general a mutant version of Scheme's macros. Is the basic coolness of templates in your mind that you can abstract over things that you can't abstract over with a class or a function?

--
"it's not rocket science" right right insofar as rocket science is boring

--Iced_Up

[ Parent ]
Yep (4.00 / 1) (#95)
by carbon on Thu Jul 18, 2002 at 05:42:37 PM EST

For me, that's templates on the nose. I always thought of it in terms of a template as being a class-class, that is, you instantize a template into a class just as you instantize a class into an object. The difference is, you can also deal with templates like classes, by doing inheretence via the placeholder names...

template <typename SomeType> class ChildTemplate : public ParentTemplate<SomeType>;


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Templates! (none / 0) (#101)
by Skywise on Thu Jul 18, 2002 at 05:51:49 PM EST

Templates are most definitely macros on steroids.. (Except they have full blown type checking)

Their main purpose is to completely unbind data type from data operation.

In C, you could only make a link list by either genericizing everything to a void* (which destroyed type safety), or by implementing a separate linked list for every data type that ever needed one.

Templates easily allow you to write the methodology once (say for a linked list), and then assign the data type on declaration.

The coolness factor comes for stuff way beyond this... Essentially when you declare a template, you declare it like this:

Template <class T> class Blah
{
     T  m_data;

public:
     void SetData(T data)
     {
           m_data = data;
     }
};

Then when you declare an instance of "Blah" you do so like this:

Blah<int>   int_blah;
Blah<char>  char_blah;

So, a basic implementation of the STL string class is really a template like this:

std::string<char>  char_string;

But with just one declaration change, you can support unicode:

std::string<wide_char> wide_char_string;

But wide_chars don't get compared the same way as regular chars, so std::string also allows you to change the comparison capabilities:

std::string<wide_char, wide_char_traits> wide_char_string;

Want your own custom sorting algorithm for char's?

// for example purposes only, don't try this at home...
std::string<char, my_char_traits> directory_name;

So now, the exact same code base, can be modified on the fly to have different functionality, without being rewritten.

And that's both cool and nightmarish...

[ Parent ]

How So? (none / 0) (#129)
by unknownlamer on Fri Jul 19, 2002 at 12:08:21 AM EST

I don't understand how Scheme macros and C++ templates can really be compared. Templates would be better compared to generics and methods in CLOS and GOOPS/Stklos. E.g. you have a GOOPS object named <container> that all of your container classes inherit from and then a generic named sum with the method (sum (container <container>)). Since you can't overload functions (for those that don't know Scheme/Lisp, Scheme doesn't have operators), templates wouldn't work very well. But when you use Guile with GOOPS (or Stk with StkLOS), you can overload functions using generics (which in reality redefines the function as a generic but has the nice side effect of setting the old function as the method for items of type <top> i.e. everything that you don't define a method for).

I don't really think that there is (or ever will be) a C++ equivalent of r5rs macros. If all you are using the macros for is being able to modify arguments, then you already have that with references, but the idea of creating new syntaxes is something isn't easily representable in C or C++ (e.g. if I were a masochist I could define Common-Lisp's loop as a macro, but try doing something like that in C++). You really have to love a language where you can define the entire language in terms of about a dozen or so primitives, with the rest as functions or macros.


--
<vladl> I am reading the making of the atomic bong - modern science
[ Parent ]
macros versus templates (none / 0) (#157)
by jacob on Fri Jul 19, 2002 at 05:02:30 PM EST

So the view that templates are purely a means for type-abstraction is pretty prevalent among people who aren't C++ gurus (a group that certainly includes me), but the way it's implemented certainly makes it count as a macro system of some kind (if you take the definiton of macros as just programs that run at compile time to turn source code into other source code). And when you see things like this and ucblockhead's comment, along with the constant guru assertions that templates are more than type abstraction, you start to think that maybe they're using them for some of the things scheme macros get used for after all.

Of course, scheme is actually built up around macros so they're much more cleanly integrated and more powerful in Scheme, but it sounds like the C++ers are using them for the same sorts of purposes.

--
"it's not rocket science" right right insofar as rocket science is boring

--Iced_Up

[ Parent ]

Err... yes.. but... (none / 0) (#160)
by Skywise on Fri Jul 19, 2002 at 06:41:19 PM EST

Templates, boiled down to their core actions, are macros with type checking.

But becaue they can be classes, and because the generated code gets resolved at compile time by the preprocessor, you can actually instantiate and "run" a class at compile time.  This make Templates really a sort-of meta-language.

However, that level of usage requires a fairly intimate amount of behind the scenes knowledge of what's going on with the compiler.  So you see them mostly used as data abstractions.

Take a look at the Microsofts' WTL/ATL classes to get an idea of what sort of real "evil" you can do with templates ( http://www.codeproject.com/wtl )


[ Parent ]

Templates... (5.00 / 2) (#73)
by Skywise on Thu Jul 18, 2002 at 03:50:22 PM EST

Though the base Java object will handle some cases that templates solve in C++ (IE when used as containers like lists), templates provide the added benefit of similar functionality over unrelated data objects.

You could have 15 gabillion classes that are in no way related (inheritance-wise) but all have the method DoSomething(), and they'll all work in the same template.

Now, do you really want to USE/NEED that functionality?!  

Eeehhh...

Operator Overloading was a good idea and still is for the well defined cases where operators are used (mathematical expressions and streams for instance, concating strings, etc)  But it's arguable that it's better to actually use method calls for those actions than to express them as operators.

[ Parent ]

probably dont need that function (none / 0) (#79)
by zzzeek on Thu Jul 18, 2002 at 04:25:41 PM EST

You could have 15 gabillion classes that are in no way related (inheritance-wise) but all have the method DoSomething(), and they'll all work in the same template.

Now, do you really want to USE/NEED that functionality?!  

No, because all those kabillion classes would just implement the SomethingDoer interface, and could be referred to by any other class as an instance of SomethingDoer.

[ Parent ]

That's my whole point... (none / 0) (#92)
by Skywise on Thu Jul 18, 2002 at 05:25:17 PM EST

Sometimes you don't want objects to be related by interfaces, but they do perform similar functionality.

For instance, suppose you had 2 completely unrelated C++ math libraries.  Their objects are not interchangeable, but they all overload the '+' operator and the '=' operator.

Using templates, you can mix and match the class libraries without having to hijack the entire object hierarchy.

[ Parent ]

hmm (none / 0) (#98)
by zzzeek on Thu Jul 18, 2002 at 05:48:06 PM EST

doesn't it get confusing to associate unrelated hierarchies like that?  how often would you want to do something like this without implementing a something like an adapter ?  

[ Parent ]
Sometimes... (none / 0) (#102)
by Skywise on Thu Jul 18, 2002 at 06:01:06 PM EST

Templates work best when you need to handle objects at their purest level (ie, to replace a void*, which is what Java covers with their base object class) and when you have objects with well defined similar behaviors, but are NOT related.

In the latter case, you don't think of the object hierarchy, but on the action being performed on a set of objects.

[ Parent ]

Action on Objects (none / 0) (#112)
by Matrix on Thu Jul 18, 2002 at 07:25:25 PM EST

Yes, which is what interfaces do. The SomethingDoer interface implies nothing about the relation of any or all the objects implementing it. It merely garuntees that they have a DoSomething() method available that conforms to a certant external interface.


Matrix
"...Pulling together is the aim of despotism and tyranny. Free men pull in all kinds of directions. It's the only way to make progress."
- Lord Vetinari, pg 312 of the Truth, a Discworld novel by Terry Pratchett
[ Parent ]

But (none / 0) (#116)
by Skywise on Thu Jul 18, 2002 at 07:52:56 PM EST

Interfaces force relationships which is not always desired.

[ Parent ]
Relationships? (none / 0) (#138)
by Matrix on Fri Jul 19, 2002 at 08:43:37 AM EST

Exactly what relationship do they force? Interfaces are not strictly speaking part of the inheritance hirearchy. They merely garuntee certant capabilities on the part of the implementing classes. Saying "Quux implements SomethingDoer" merely garuntees that Quux has a "public void DoSomething()" method. Where exactly is the relationship this forces?


Matrix
"...Pulling together is the aim of despotism and tyranny. Free men pull in all kinds of directions. It's the only way to make progress."
- Lord Vetinari, pg 312 of the Truth, a Discworld novel by Terry Pratchett
[ Parent ]

relationships (none / 0) (#145)
by zzzeek on Fri Jul 19, 2002 at 11:33:29 AM EST

its because if you are using two different libraries that have nothing to do with each other, and they each have no knowledge of the common interface you want to use, you now have to write adapters of some kind that implement those interfaces and delegate their functions to those two libraries.

which personally I would prefer doing, since its clearer.  

[ Parent ]

Relationships. (none / 0) (#149)
by Skywise on Fri Jul 19, 2002 at 11:47:29 AM EST

Any class containing an interface A now becomes related to any other class that contains an interface A.

Which may not necessarily be a bad thing.

[ Parent ]

Relationships (none / 0) (#166)
by Matrix on Sat Jul 20, 2002 at 09:43:49 PM EST

In this case, its a good thing. They have a common DoSomething method that you want to call on many different sorts of classes. If you have a way to garuntee that class you're being given has a DoSomething(), it simplifies matters greatly. And makes your code much more readable.

I know one can do this in C++ with virtual/abstract base classes - I use this all the time when I code C++.


Matrix
"...Pulling together is the aim of despotism and tyranny. Free men pull in all kinds of directions. It's the only way to make progress."
- Lord Vetinari, pg 312 of the Truth, a Discworld novel by Terry Pratchett
[ Parent ]

In Java, you're correct... (none / 0) (#171)
by Skywise on Sun Jul 21, 2002 at 04:27:32 AM EST

But C++ has one more template trick that Java doesn't... Template FUNCTIONS.

Now I'm not 100% comfortable with this issue yet, so bear with me if I'm wrong, and here goes:

A template function is declared outside of the class and acts as an operator on particular data types:

int template<T> operator+(T, int);

What's mind tripping about this is that you can add, at a later date, new incarnations of this method that support data types that might not have been written at the original time of coding:

int template<T> AddTo(T, newDataType);

So when you use a template class for the manipulation, you can add functionality *without changing the interface*.  And this is why you're seeing such a large shift to compositing classes over inheritance in C++.  But this is only true of C++ and not Java, in which case interface inheritance is the (only) way to go.  (Unless Java gets templates)

[ Parent ]

heh... (none / 0) (#176)
by zzzeek on Sun Jul 21, 2002 at 11:47:33 PM EST

I'd love to hear what your boss has to say when you show him your latest "mind tripping" code...

[ Parent ]
As a general thing... (none / 0) (#118)
by carbon on Thu Jul 18, 2002 at 07:59:28 PM EST

Java, from what I can tell, uses named interfaces to allow containers and such to require certain attributes of a contained type. That is, a container contains an implementation of X interface, and you hand it some things which implement that interface. This approach has the advantage of letting you require more complex and specialized things from what you're containing, and not potentially confuse it with the same-named but different-purposed methods from something else entirely.

However, C++ can do this too: It has interfaces and such in the form of virtual base classes. Then, you use a template with that by specifying that as the placeholder type when concreting a template class, and the template deals with the virtual base class merely through operators and algorithmic operators.

For example, this is fine with containers: they shouldn't depend upon specifics of what they're containing other then reordering, as only the container's client is actually concerned about the content in the container. If you need an additional interface implemented in the contained object, just specify that type when concreting the template.

Templates are there to implement generic programming, and the operators seem to do all the operations that are required of generic programming, from what I've seen. If a template needs to contain something of a specific interface, that might be bad design. But if you want to do that, you can anyways, perhaps through merely making a pointer cast to the interface in question, like so:

InterfaceXYZ* check = new ContainedType();

Since C++ interface types are also real class types, you can create pointers to them (though since they're usually pure virtual, you can't construct one). If the contained type actually implements InterfaceXYZ, this is a perfectly valid polymorphic cast. You never even need to do anything with this pointer; merely the fact that the contained type can be converted to it safely is enough. In fact, this code never needs to run once, it simply needs to exist privately and the compiler will check it for type safety anyways.

The only disadvantage is that the contained type must then have a default constructor implementation, but nearly any template is going to require that anyways, so it isn't an especially big deal.

C++'s operator overloading is also good for generic programming. Operators define some general operations that are common to lots of things. People who aren't used to C++ may not be aware of just how many operators it has:

  • The regular comparision and equality operators, including comparison with arbitrary types.
  • The assignment operator, which is pretty much equivalent to a copy constructor (primitives also support copy constructorish calls, btw).
  • The bitshift operators, used more commonly in C++ as the streaming operators. This is great for generic I/O objects.
  • The typecast operators, which allows for the compiler to create automatic casts. For example, creating a cast operator for your class to int allows users to do a lone test of your class in an if statement.
  • The dereference operator, which can be overloaded so you can make pointerish classes. For example, iterators often dereference to the contained item they represent.
  • The function call operator, which is the basis of functors; you can construct an instance of a class and call that instance. This is a handy way to have STL containers use alternate means of getting things done. Most of the STL containers allow you to pass an Alloc function object to define how the container allocates memory.

What all this comes to is, I just find C++'s capabilities for generic programming and containers of this kind to be better. But on the other hand, I've been told by Java developers here that Java designs rarely provide any external access to containers, such as by returning or accepting containers besides arrays as function arguments. So, all you have to do is maintain internal safety and you don't need to bring in any of the additional protection offered by templated generic programming. Different design views produce different langauges...


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Operators... (none / 0) (#133)
by bodrius on Fri Jul 19, 2002 at 04:16:51 AM EST

The problem with operators is that they can be grossly misused, much worse, I think, than any other feature in C++. And they are. A lot.

After all, as confusing as pointer arithmetic can be for the naive programmer, something like:

c= *p1 +(int)**p2++;

already gives him/her a warning of what is about to happen. Caveat emptor and all that.

The same cannot be said about:

c= p1 - p2

On the other hand, operator overloading are the thing I miss the most in Java, even more than templates. Here's why:


Integer a = new Integer(23);
Integer b = new Integer(40);
Integer c = a + b;

Wouldn't it be nice if this code worked?

 
Freedom is the freedom to say 2+2=4, everything else follows...
[ Parent ]

So... (none / 0) (#135)
by carbon on Fri Jul 19, 2002 at 05:53:13 AM EST

It should be obvious you're messing with pointers. After all, how would you even know what the statement did at all the first place without knowing the types of c, p1, and p2, and seeing the lines above and below this one? That's true of nearly any individual line of code in any language; out of context, it can easily make no sense at all.



Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Operators can have misleading context (none / 0) (#139)
by bodrius on Fri Jul 19, 2002 at 09:12:23 AM EST

Namely, I can put that line c=a+b in the source code of a full application, and it will probably still give no clue as to what it is actually doing.

That's the whole point of operators, after all. To hide such details. Whatever "+" means is completely hidden from the programmer, and there can be a lot of custom logic there, including some coercion of the data types.

So, if I have a program that goes:


TypeA someFunction(TypeA a, TypeB b)
{
   return a+b;
}

It's not necessarily obvious what it's doing. It depends on the behavior of the + operator with TypeA on the left, and TypeB, or a superclass of TypeB, on the right, right?

Which may or may not be consistent with what would be expected from the "+" operator... I don't think anything stops the "+" operator from having side-effects on the objects, for example.

Which means that, given more complicated code than this (practically any code), it can be very easy to miss an overloaded operator and its effects.

It can also be very easy to type c=a+b expecting a given behavior (like say, addition) without thinking twice. Part of the point of overloaded operators is to make coding special cases, like matrix arithmetic, natural and fluid, right?

Of course, they can be used properly. And should be used properly. And as I said in the previous post, I miss them when they are used properly.

But a misdocumented, misused overloaded operator is more dangerous than any other bug, simply because you could read all the code and (without good documentation) it's invisible, and because it affects a lot code that other programmers were calling implicitly.

For example, it's easy to find all your dependencies on the method call TypeA.doSomething(TypeB). Not so easy to find, filter and deal with all the "+".
Freedom is the freedom to say 2+2=4, everything else follows...
[ Parent ]

Well (none / 0) (#162)
by carbon on Sat Jul 20, 2002 at 01:31:04 AM EST

Again, how is that different from any other operator? I could build a class with methods like Bob() and Jane(), and it would be basically incomprehensible. Or, I could build a class with methods like getValue and setValue, say, and have them do each other's expected jobs. The operators are just like that; they define some standard method names with fairly recognized contracts, and violating them in your code.

I'm glad you understand that operator overloading can be used right, but I'm sure that it's not particularly worse in real use then any other badly designed method. After all, C++ is a type oriented langauge; if you see c = a + b, your first thought is likely to be "What types are c, a, and b?" and from there you just look up the classes in question if it behaves unexpectedly.

There are probably ways to use operators to intentionally create confusing code, but you can do that in any number of other ways, in any langauge. I'm reminded of an example of a guy who named a C++ macro 'Return'...


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Templates - compile time (static) checking (5.00 / 3) (#100)
by DodgyGeezer on Thu Jul 18, 2002 at 05:50:09 PM EST

"Templates are less necessary (though some people still desire them) since every object in Java derives from the base class Object and any kind of library, such as the standard collection classes, can deal with passing every kind of object (and native types wrapped in objects, to the chagrin of some) based on the Object superclass. The main argument for templates is that there is a slight performance hit associated with all the casting this introduces. Java likes to choose simplicity over small performance increases, quite often"
For me, the main benefit of templates is compile time checking. Having a collection based off "Object" is almost no different from C's answer: using "void*". (Yes, I know: Java does support introspection and exceptions for bad casts, but that might not show up as a bug for a long time.) The compiler is a powerful tool when it comes to rooting out bugs earlier on in the development cycle - use it! To achieve compile time (static) type checking for a generic collection class in a language that doesn't support parameterisation means creating implementations of the collection by hand for each type of object you want to store.

[ Parent ]
Java NEEDS Templates (2.00 / 2) (#132)
by bodrius on Fri Jul 19, 2002 at 04:03:00 AM EST

Sure, they ARE less necessary.

But that's like saying that clothing is less necessary if you telecommute.

Waiting for ClassCastExceptions to happen is not a solution, and introspection as amazingly useful as it is, is not a solution for this particular problem.

That's why so many programmes end up coding a wrapper/extension for the data structure that provides the restrictions. Exactly the kind of thing that should be automated.
Freedom is the freedom to say 2+2=4, everything else follows...
[ Parent ]

templates.... (none / 0) (#143)
by zzzeek on Fri Jul 19, 2002 at 11:29:14 AM EST


That's why so many programmes end up coding a wrapper/extension for the data structure that provides the restrictions. Exactly the kind of thing that should be automated.

But I like typing....

[ Parent ]

As a C programmer... (none / 0) (#170)
by DavidTC on Sun Jul 21, 2002 at 02:38:02 AM EST

...and pretty much only a C programmer, though I did have C++ in college I've forgotten all the template stuff, I have to point out you can't really use void * in the way you can use templates in C++, I don't think.

You have to actually cast a void pointer to something else for it to work. So you can't say 'I know this struct has an int named 'value'', and access it. You have to cast it to something else (hopefully the correct type) and access it.

Of course, I don't remember C++ that well, possibly you have to do that in C++ also, but I was of the impression you could somehow access objects that you know follow a template and get useful infromation out of them without casting them.

-David T. C.
Yes, my email address is real.
[ Parent ]

Bags of tricks ?? C++ vs Java vs ?? (3.00 / 1) (#134)
by treefrog on Fri Jul 19, 2002 at 05:15:23 AM EST

So, for what its worth, I'd like to throw my 0.02 Euro's worth in.

Ive first started using Java in about 96 or 97. At the time, I have to say it was an interesting experience. I found that the garbage collection didn't work properly. On the other hand, the idea of a cross platform graphics library was very neat. I know that the Swing libraries are much more highly thought of than the old AWT libraries. At that point Java seemed very highly focused on being a "cross platform C++", with a good support for client side visual stuff. As a C++ programmer doing simulation work, I found system.out.println to be a pain compared to cerr !

Frankly, I gave up on Java because (for the work I was doing) C++ was eventually a better fit. I could live without the graphics at the time (and I switched jobs).

My own opinion of Java was that both its strength and its weakness is that it was trying to be a cross platform C++. It did appear to get a lot of things right that C++ did seem to have wrong at the time, and I appreciated it for that, but essentially it seemed to be spending a lot of time trying to be a better C++.

More recently I have discovered Ruby. I've now been working in Ruby for several years. I find it complementary to C++. There are many things that I would not want to attempt in C++, but which I will happily do in ruby. Pattern matching, regexp processing, perl type stuff. Plus easy socket code and multi-threading. OK, so I do the latter 2 in C++ as well, but they are very simple in Ruby. But Ruby is more in the Python or Perl space than C++ - it is not trying to do the same job. It's heritage comes more from Smalltalk and Lisp and CLU and well, anything that seems sensible.

I don't really want to put any language down. After all, they are all have equal computational power (even Befunge!). But choose your language for the job. Unless I had a good reason (and yes, there are good reasons, like writing user-space code for mobile phones, and server-side applications which I know nothing about), I would choose C++ above Java. But generally, I would choose my language on the merits of the application - no one size fits all. And it is probably easier to learn a new language, than struggle with the wrong one.

regards, treefrog


Twin fin swallowtail fish. You don't see many of those these days - rare as gold dust Customs officer to Treefrog
[ Parent ]

swing... (none / 0) (#142)
by zzzeek on Fri Jul 19, 2002 at 11:26:20 AM EST

personally I think the abandoning of the original AWT model, that is wiring native widgets to Java classes, was a mistake.  Swing is a really huge and rather bloated API and was an enormous reinvention of the wheel, and was way overkill for a huge amount of applications that just needed basic GUI support.  

Whether or not it has a place, it took an incredibly long time to be even moderately useable, and still places more resources on a VM than I think is normally appropriate, especially for small applications.  There are many many applications that could have been successful if Sun had only made the slightest attempts at making the native AWT at least reasonably useful....Java earned the biggest bad rep in the world due to the poor and unfinished AWT implementation (since despite its dominance in the field of server side web applications today, a whole lot of PR seems to derive from the GUI and its performance, or lack of.) Would have been better if it just didnt have a GUI....let third parties compete with various native and non-native GUI packages.

[ Parent ]

Eclipse's SWT (none / 0) (#172)
by mhandis on Sun Jul 21, 2002 at 05:28:01 PM EST

Try SWT. It comes with the (free) Eclipse IDE, at www.eclipse.org.

It has a native OS look and feel, and it's quite fast. The Eclipse website has a few articles that help getting started with it pretty quickly, and you can also download example code.

It doesn't really rival Swing... it is more like a fast and complete AWT.

If you haven't tried it, the Eclipse IDE (which is written with SWT) is not bad at all as a Java IDE, either.

[ Parent ]

Java weenies whining about C++ (4.00 / 5) (#78)
by marcos on Thu Jul 18, 2002 at 04:17:28 PM EST

This isn't addressed towards the article, but towards the comments.

One of the most annoying things in the world is when programmers come fresh out of college, and because they have only learnt Java, and it is the only language they are somewhat intimately familiar with, claim that it is the greatest language in the world, and live the rest of their lives comparing all other languages to Java.

Get it through your head now, different languages are there for different purposes. C++ is an excellent language once you are familiar with it, and the syntax is also good.

And I hate those oldtimers who say that C++ is bloated hackfleisch language, and that C is the reincarnation of Jesus come to save us all. C is out. Nobody listens to techno.

Admit it, you just are not flexible enough to learn a new language, that is why you cannot move on from C. In the same way, you college graduates who insist on using only Java, Earth to you, its time to make your way down. And we'll hang out a sign - welcome to the real world, Java is bloated and slow, and nobody uses Java.

Java advocates who deride C++ are going to land in VB purgatory. Believe in C++, and you shall enter programmers heaven. Amen.

youre chasing windmills (4.00 / 1) (#91)
by zzzeek on Thu Jul 18, 2002 at 05:21:01 PM EST

Since my comment is the only comment I see that relates to Java, I will point out that theres nowhere that anything I say expresses the views that  "everyone should only use java", or "C++ sucks", or "java is the greatest" or trying to define C++ in terms of its relation to Java, or anything like that, only that Java is a useful langauge that is different from C++ and possibly does not need to have the identical features.

I also didn't say I am a recent college graduate, which would be because college was about 10 years ago for me.  So it seems like you are responding to some other kind of post that you saw somewhere else, becuase its certainly not mine.

I imagine this mysterious post you're responding to exists in the alternate universe you're obviously residing in, the one where "nobody uses java".

[ Parent ]

Languages: C++ vs. Java (none / 0) (#144)
by mlepage on Fri Jul 19, 2002 at 11:29:56 AM EST

I say this as someone who is near-expert in both C++ and Java. I prefer C++, but I do use both, depending on what I'm doing. A good programmer has many tools and chooses the best one. But Java gives me many pet peeves, and I will jump on the "Java gives you lots of high level APIs" comment in the original article. Sure, I can make a Window, load an image, and play a MIDI file in standard Java. But I can't create a temporary directory (no tmpnam). I can't use a common programming paradigm for resource control because I can't force an object to be destructed. I can't say something is const. I can't dereference an iterator. Most of the Java APIs are kludgy. You can tell they were written by a million people. Just look at the three ways you can do properties and fire events: each part of Swing uses its own style. Anyways I could write a book about Java's shortcomings, but I digress. Maybe I should compose a huge Kuro5hin article about it. But I'm sure it would just incite flames. Save them. I went through my Java rebirth and woke up loving C++ even more. It also has its warts, but they're not nearly as bad.

[ Parent ]
COBOL (3.00 / 1) (#109)
by vambo rool on Thu Jul 18, 2002 at 07:03:02 PM EST

Here's something to consider when arguing about the microshare of the market that one language or another has. Read this all the way through. It's fascinating.
Consider these facts from industry watchers: 70 percent of the world's data is processed by COBOL and nine out of 10 ATM transactions are done using COBOL. Thirty billion online COBOL transactions are processed daily; 492 of the Fortune 500 use COBOL, including the entire Fortune 100, and current COBOL investment tops $3 trillion. You get the idea--these legacy systems still have an important role to play in business today.


False, or rather incorrect (4.00 / 1) (#184)
by hugues on Wed Jul 24, 2002 at 01:20:31 AM EST

If you follow the links all the way to the original reference, the quote becomes:

"70 percent of the world's BUSINESS data is processed by COBOL."

I have no trouble believing that, but by my rough guestimate 99.9% of the world's other kinds of data is processed by C or assembly. Namely in routers, O/Ses, TCP/IP stacks and whatnot that make up the Internet. The business/financial data that is floating around the world is nowhere near as big as what's being exchanged on the Net these days.

And by a wider definition of what constitutes business data I'd say that at least 80% of it is processed by Microsoft Office.

Care to contradict me?

[ Parent ]

Aren't those the pre y2k numbers? (none / 0) (#189)
by thogard on Sun Aug 04, 2002 at 11:08:21 PM EST

To run Cobol you need a large chunk of iron and most of the fortune 100 data centers I've been in have large spaces where the water cooled dinos used to live.  If you add up the number of PCs in the world (70 million new ones per year?) and figure how many minis and mainframes that run cobol you find that its an ever decreasing number.  Cobol used to be used for accounting system and now that EDS outsources most of that (and is moving away from Cobol) and most small businesses use something like quickbooks that was written in C++ it does appear to have an ever decreasing slice of the pie and I don't think its been 70% since the mid 80's.  A modern web server will process more data in a day that many of the large data centers could in a year.  For example my web server did 45,000 transactions in the past 4 days and moved 1.5 gig of data.  The old 3081 I used to cuss at would be hard pressed to find 45,000 records in a data base in a day.

The ATM backends tend to be solid bank systems so I could see where 90% of every ATM transactions will touch some cobol system somewhere but may of the ATM's are running programs writeen in Pascal talking to a network control that was written in C which talks to a vpn written in C which talks to an acquirer system written in C++ or Java which builds batches that are imported through old JCL systems into banks that print out statments with Cobol in laser printers that are have their frimware written in forth.

[ Parent ]

Also: zlib, libpng (4.50 / 2) (#117)
by SeanReardon on Thu Jul 18, 2002 at 07:56:20 PM EST

At my work we make extensive use of zlib and libpng.  Both have proven extremely useful.

We made aggressive use of zlib in our port of Half-Life to the ps2 (smaller data files == less time waiting on a read to complete).

I'm pretty sure we are still using the png image format for some of the textures in our bond game.

Heh (none / 0) (#121)
by carbon on Thu Jul 18, 2002 at 08:20:35 PM EST

Yeah, forgot about gz and png compression.

Though, where do you work, porting PS2 games? Do they have an opening? ;-)


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
Sorry, no openings (n/t) (none / 0) (#128)
by SeanReardon on Thu Jul 18, 2002 at 10:48:33 PM EST



[ Parent ]
The obvious (none / 0) (#186)
by JPriest on Thu Jul 25, 2002 at 03:17:14 AM EST

Though, where do you work, porting PS2 games? Do they have an opening? ;-)

Obvious, his URL is http://www.gearboxsoftware.com

Once, Sean ate a Taco Bueno product every day for ninety days.

[ Parent ]

Trolling (2.50 / 2) (#122)
by sypher on Thu Jul 18, 2002 at 08:43:27 PM EST

Discredits the content of the article, i dont have the first clue about C other than knowing what it is.

I enjoyed the article but suddenly wonder what basis the original and the ILT have for differential.

Who to believe if i have no idea of what C is?

Yesterday my diary went on about trolls ruining the discussion, i see their maniacal antics in my hidden comments, if they are there for two days running, kill the fscking account already.

I dreamt of it once, now I fear it dreams of me
Well... (none / 0) (#130)
by carbon on Fri Jul 19, 2002 at 01:50:00 AM EST

This is an article for people who've learned to code in some other langauge, have switched to C++, and are suddenly wondering where the API's they used to use for <threading/string processing/etc> are. It isn't intended to be a guide for people who've no experience with C-ish langauges at all.

Moreover, there's been very little trolling on this story as far as I can tell. And, what's an ILT?


Wasn't Dr. Claus the bad guy on Inspector Gadget? - dirvish
[ Parent ]
ILT > Ivy League Troll <NT> (none / 0) (#141)
by sypher on Fri Jul 19, 2002 at 09:54:34 AM EST



I dreamt of it once, now I fear it dreams of me
[ Parent ]
ICI (4.75 / 4) (#125)
by tpv on Thu Jul 18, 2002 at 10:33:22 PM EST

So to conclude, Lua is, under many but not all circumstances, a good alternative to larger scripting languages such as Python

Another alternative would be ICI.

Small, full-featured,fast, free.
It is designed to be usable in embedded situations, so it is very small.
It has regexp support, full programmng constructs, OO, etc.
Initial testing on version 4 (soon to be released) indicates it is faster than perl, python and ruby (although as always YMMV).
ICI is in the public domain.

I'm quite fond of ICI, but obviously is isn't the solution to all tasks. It has less modules than perl/python/ruby, and the syntax may not appeal to everyone.
--
"...More [people] have been bombed from the air than have flown ...modernity as a cultural outlook remains a rarity, leaving post-modernism a

Another cool tool (and book) (4.50 / 2) (#150)
by voltron27 on Fri Jul 19, 2002 at 12:08:10 PM EST

Greetings,

Another thing I've found highly useful is Loki (available at sourceforge.net/projects/loki-lib. This is a generic-design and pattern-oriented c++ library.

The library is very good, providing singletons, functors, smart pointers, factories, visitors, and multimethods. However, what is even better is reading the book, which is where the code really comes from. This book is "Modern C++ Design" by Alexandrescu. I suggest every C++ programmer run out and buy it right now. The book focuses on generic programming techniques with c++.

Before reading this book, I was frightened of templates. See, when I learned c++, template support was really bad, and the professor basically said, "well, don't worry about it." Templates are now pretty well supported all around, but using them? That's another question. If you were like me, and you really don't dig templates oh so much, do yourself a favor: get the book, get the code, and study both. Both have made my code much, much more...interesting (and better, too :)

Loki (2.00 / 1) (#153)
by ucblockhead on Fri Jul 19, 2002 at 01:45:14 PM EST

Unfortunately, Loki hugs the leading edge of the C++ standard, so a lot of compilers can't handle it yet. (Most notably Microsoft's.)

And yeah, anyone who thinks templates are worthless needs to read that book.
-----------------------
This is k5. We're all tools - duxup
[ Parent ]

There's a complete port of Loki to VC7 (nt). (1.00 / 1) (#168)
by i on Sun Jul 21, 2002 at 01:43:14 AM EST



and we have a contradicton according to our assumptions and the factor theorem

[ Parent ]
valgrind (none / 0) (#156)
by j1mmy on Fri Jul 19, 2002 at 04:15:59 PM EST

valgrind  finds memory management problems. I still use memprof for leak-checking (the gui is nice), but valgrind can root out tons of other errors. It looks like libcwd does some similar things, but valgrind is completely standalone -- no need to recompile or link against anything.

Nice but slow (none / 0) (#183)
by hugues on Wed Jul 24, 2002 at 01:08:26 AM EST

The main problem with valgrind is the speed. The binary code is re-interpreted by a virtual machine so the code slows down by a couple of order of magnitudes.

I only use it in extreme cases.

[ Parent ]

you only need to use it in extreme cases (none / 0) (#188)
by j1mmy on Fri Jul 26, 2002 at 02:42:16 PM EST

In general, you can knock out a large number of bugs with a single valgrind run. You don't need to run it on every build unless you build very infrequently.

[ Parent ]
Hmmm, trouble with nVidia GL (none / 0) (#187)
by runlevel0 on Thu Jul 25, 2002 at 02:43:35 PM EST

Looks fine, but it does not support nVidia GL.
A real piti; I jumped straight to the site to download the prog, but it happens that I am developing nVidia-related stuff...

 

[ Parent ]

The C++ Programmer's Bag of Tricks | 190 comments (172 topical, 18 editorial, 2 hidden)
Display: Sort:

kuro5hin.org

[XML]
All trademarks and copyrights on this page are owned by their respective companies. The Rest 2000 - Present Kuro5hin.org Inc.
See our legalese page for copyright policies. Please also read our Privacy Policy.
Kuro5hin.org is powered by Free Software, including Apache, Perl, and Linux, The Scoop Engine that runs this site is freely available, under the terms of the GPL.
Need some help? Email help@kuro5hin.org.
My heart's the long stairs.

Powered by Scoop create account | help/FAQ | mission | links | search | IRC | YOU choose the stories!