Which language is best?
James Stanley

I just read an article on Slashdot about Compiled vs. Interpreted/JIT Compiled languages. It seems to suggest that Interpreted/JIT Compiled languages (mainly Java) run faster when written properly and are easier to port or don't need any porting.
1.) Is Java any easier than C++?
I was just wondering because if so that would significantly improve my development time because I have to compile for MacOS, Linux, Windows, DOS, etc. and on every platform I have to change stuff.
2.) What would be the disadvantages of using an Interpreted/JIT language?

miran
Quote:

1.) Is Java any easier than C++?

No. It's the same.

Quote:

2.) What would be the disadvantages of using an Interpreted/JIT language?

You need an interpreter/virtual machine to run programs. Most programs take a long time to start. Programs can require more memory.

Billybob

It would have been wise for you to read the comments on Slashdot as well.
Boils down to this: Java is not C++ 2.0. What I mean by that is that it's a whole different tool, not something to replace C++ or any language for that matter. Same goes for Interpreted languages. They are not inheritly better than anything, they are just different.
So:
Use the right tool for the job

If you're interested in Java, study it. Learn for yourself the advantages and disadvantages. Because whether something is easier to use or not depends on the coder. I personally love coding in PHP, others don't. It has nothing to do with solid, conrete advantages or disadvantages. I just like PHP, and thus I code better and faster in it.

EDIT:

Quote:

run faster when written properly

It's either the other way around or both. Native programs can run faster if written properly. Remember, Interpreted langauges when run through JIT end up as native code. So how could it ever possibly be faster than native code?
The reason why it seems to be faster is that sometimes the JIT'r can optimise the code on the fly. Such is the case with mathematical calculations, for example. But you could do the same in native code if you wanted.

ReyBrujo

Java is fast, but still hasn't reached the point of a native executable when compiled with aggressive optimizations. As for JIT/Interpreted languages, you usually need to ask people to install the framework. Assuming everyone has installed the JRE package is a mistake.

HoHo

For most games Java is fast enough. I'm sure it is possible to code Far Cry or Quake4 in it without losing too much speed assuming most of the hardcore math is done using JNI*.

*) JNI aka Java Native Interface, a way to use external dynamic libraries aka DLL's or .so's.

I would say that coding in Java is easier than in C++ but quite a lot of that comes from IDE. When you code Java there is not many reasons not to use Eclipse, most the best opensource IDE and perhaps even best of all IDE's ;)
Another thing that makes Java easier is huge standard library. Basically there isn't many things that aren't already there. If it isn't then most certainly there is some library that you can use. E.g for OpenGL there is jogl, for OpenAL there is joal etc.

Two things I miss in Java are true templates and operator overloading.

ReyBrujo
Quote:

and operator overloading.

How so? I thought you could overload Integer.Add :P

HoHo

That is not operator overloading, that is function overloading ;)

Indeterminatus
Quote:

Quote:
1.) Is Java any easier than C++?
No. It's the same.

One might argue that Java is easier to learn than C++ because it is not as complex. Programming in itself is of course not related to a language.

A J

Dont confuse programming with scripting.

C++ can be used for both, most others can't.

Marcello

I can code a million times faster in Java than C++. Instant compile (Eclipse), and no segmentation faults makes a world of difference.

However, I think English is the best language.

Marcello

Evert

I always thought it might be possible to make a programming language with a grammer structured after Latin, but I never sat down and worked out the details.
I may someday, just for the fun of it.

ImLeftFooted
Quote:

I may someday, just for the fun of it.

Someone made a sheakspearian programming language, its somewhere on the internet.

Quote:

1.) Is Java any easier than C++?

I'd have to go with yes. If only for the lack of memory management, though there are other aspects of Java that have been simplified and dumbed down a lot as well.

Quote:

2.) What would be the disadvantages of using an Interpreted/JIT language?

No-one seems to find the end-user installing the JVM as a disadvantage. I don't understand why. Personally I hate the thing. It sits there eating my CPU cycles with no way to turn it off. I cant even find the name in the task list to kill it. Its like have an ex-girlfriend who thinks shes such hot shit that she wont leave your apartment, and shes cut all the phone lines so you cant call the cops.

That aside, to me it makes sense that I as a programmer do a little extra work to ensure that the application will run on multiple OSes. A little extra work by the programmer to make the user's life easier to me is always worth it. But maybe I'm biased from programming too many GUIs.

Evert
Quote:

Someone made a sheakspearian programming language, its somewhere on the internet.

That's not really the sort of thing I had in mind though.

Archon
Quote:

1.) Is Java any easier than C++?
I was just wondering because if so that would significantly improve my development time because I have to compile for MacOS, Linux, Windows, DOS, etc. and on every platform I have to change stuff.

Syntax-wise, I would say it's relatively similar. Except Java is PURE Object Orientated, while C++ can still have the procedural nature of C. However, maintaining 3 different versions of the same software would be simplified with 1 single executable.

Quote:

2.) What would be the disadvantages of using an Interpreted/JIT language?

Speed and memory usage. However, C# (I think Java too), uses a garbage collection which can free memory that is not used - so with programs that crash and have memory leaks... it's only a matter of time that the memory usage catches up - unless you reboot often, but that's a Windows user thing ;)

Quote:

I always thought it might be possible to make a programming language with a grammer structured after Latin

Like BASIC with an extra hundred unnecessary keyboards? ;D

Quote:

Its like have an ex-girlfriend who thinks shes such hot shit that she wont leave your apartment, and shes cut all the phone lines so you cant call the cops.

What a perfect analogy.

Karadoc ~~

Yay! A language flamewar in the making. :)
Here's my opinion:
C / C++ -> good
Java -> Bad
Python -> Ok
everything else -> don't care / don't know

And so, as people typically say in these sorts of threads: Use the right language for the job. Different languages are good for different things. For example, I use [my favourite language] for [almost everything], and [my second favourite language] for [a couple of other less important things].

Ok, my point is that it doesn't really matter much which language you use. Most languages can do basically everything. Pick the right language for the job; and if you don't know which language is the right one, just pick the language you are most comfortable with.

James Stanley

Ok, Thanks guys. I think I'll stick with C++ for now then. I started programming in Java, but that was a bit complicated with no prior programming experience at all, I thought I might go back and have another go some time.

Jonatan Hedborg

Im a C++ programmer myself (or so i like to think), but after a three courses of java at uni, i must say that java has it's merits.
It is a lot easier, for many reasons, including; no memory management, no messing around with header guards, circular dependencies etc, the API is HUGE and have functions for reading and drawing bitmaps, playing sounds etc, it has a more human-readable syntax (extends instead of : ), has two types of for-loops, it has interfaces and it has eclipse which will make you cry when you use Dev-C++ again :(

It is however quite the memory hog, and all users will need the RTE, preferably the latest version if you want to use generics (and you do).

As for C++, i'd say that it's THE language of choice for game-makers everywhere. The industry uses it. There is fast and easy access to hw-rendering etc.

Basically, Java is a sleek sport car (with a dvd player for when you are stuck in trafic) and C++ is a 18 wheel diesel truck.

They both have their uses. Java is great if you want to make a GUI application quickly or a smaller game, while C++ would be great if you want to make a high-performance 3D game.

This is all imo naturally :)

James Wyman

Java with something like jbuilder is very easy to create aplet programs. c++ is much more powerful and allows you access to many things you are not privy to in Java.

Archon
Quote:

Basically, Java is a sleek sport car (with a dvd player for when you are stuck in trafic) and C++ is a 18 wheel diesel truck.

I'd say the other way around.

Thomas Fjellstrom
Quote:

I'd say the other way around

Hes not referring to the speed :P

Archon
Quote:

Hes not referring to the speed :P

Yeah but in his post he said Java is a memory hog (size) as well as it's standard set of API that comes with it (is big too).

And to me, C++ is a cooler language, sports cars are cool ;D, but they can crash easily with an amateur driver. With rigs, their crashes would be destructive (if the JVM crashed maybe?) :)

Of course, if you want to keep your sanity, ignore what I just said.

HoHo
Quote:

With rigs, their crashes would be destructive (if the JVM crashed maybe?)

Big rigs don't crash because they have Autodrive systems installed ;D

Also, so far I haven't seen or heard that JVM has crashed. If it has it had to be something else that caused the problem, not the program or JVM itself.

Jonatan Hedborg

A sport car is not very fuel effective, it is however full of fluffy and shiny things.
An 18 wheeler is tough, powerful and effective. But it aint pretty.

That was the thought behind my analogy.

Peter Wang
Quote:

I always thought it might be possible to make a programming language with a grammer structured after Latin, but I never sat down and worked out the details.
I may someday, just for the fun of it.

http://www.csse.monash.edu.au/~damian/papers/HTML/Perligata.html

BAF
Quote:

Speed and memory usage. However, C# (I think Java too), uses a garbage collection which can free memory that is not used - so with programs that crash and have memory leaks... it's only a matter of time that the memory usage catches up - unless you reboot often, but that's a Windows user thing

... 2k/XP clean up memory leaks automatically. This is why I can go for months on end without rebooting. :P

amarillion
the title said:

Which language is best?

Perl

I'm sure you take my word for it.

Evert

:D
Thanks for that. I'll have to check that out sometime.

nonnus29

You guys are sooo gay. Java and C++ are nearly identical. If you want to talk about significantly different languages then Perl is a good start, then scheme, sml, haskell, prolog, ruby, etc... Even javascript has functional aspects. ;)

Jonatan Hedborg

You may or may not have noticed that the OP's question was "What is better, java or c++?" not "what language is most different from Java and C++?"

And if you have used Java and C++ for any extensive period of time, you would know that while they are syntactically very similar, their uses, strengths and weaknesses are quite different.

GullRaDriel

To the OP:

When it come to work in a company, you must use what they allow you to use.

For your own production, the fact is that:

THE BEST LANGUAGE IS THE ONE YOU ARE BETTER AT.

tobing

Makes me think of this old article about 'Real Programmers don't use Pascal', comparing Fortran to Pascal and C and other programming languages. How did they say it? "You can write FORTRAN programs in any programming language." ...

GullRaDriel

X is for quiche eaters.

Replace X with one following the rule named #must_match_a_programming_language_name#

Evert
Quote:

You can write FORTRAN programs in any programming language.

;D
So true!

Steve++
Quote:

Java and C++ are nearly identical.

Heretic!

I started learning C++ about a year before Java. I found Java programming much more productive, but used C++ because Java wasn't yet a formidable game language. Things have certainly changed now, but the game industry is quite predictably slow to catch on. It doesn't matter that Java is a memory hog. The fact that the JVM eats a big chunk of the heap at startup isn't a problem, because it is just doing what most big games do anyway.

For me, distribution is the overriding factor in language choice. If I want to make a game that can be quickly downloaded, I'm probably not going to be too comfortable with requiring the JRE be installed. But if I'm distributing on CD or some other physical format, then I can just include the latest JRE and have the installer install it if needed. In the former case (Internet distribution) I would most likely prototype in Java and perform a native conversion once the game is finished.

Marcello

On the other hand, you can require Java Web Start, so even distributing on the web is not that big of a deal.

Marcello

axilmar

Coding is generally much easier in Java, thanks to garbage collection and its huge set of libraries. Java is quite fast, with only exception being Swing (which is slow due to implementing its own window manager). Java programs are portable with minimal fuss.
Java programs tend to be slower than C++ programs, because of all the work being done in the background...but I do not find the performance issue critical for most applications.

If you need the absolute fastest speed possible, go with C++. But be prepared to be mentally tortured by an endless stream of uncontrolled crashes, memory corruption, wild pointers, etc. But, in the end, if you make it, your app will be fast!

Evert
Quote:

But be prepared to be mentally tortured by an endless stream of uncontrolled crashes, memory corruption, wild pointers

Am I the only one who hasn't had problems with pointers and memory management?
I probably had some difficulty the first time I tried to use them (in Pascal), but I've never had a problem in C (or C++).

Thomas Fjellstrom

I had no end of troubles when I was learning C, with Win95. Oh how I hate win95.

23yrold3yrold

Well I didn't learn on Win95. :) But pointers and memory management are simple once you understand them. Haven't given me problems in ages.

Jonny Cook

I usually prefer to program in HTML.

Matt Kindy

I prefer C to any language SO_FAR
#define SO_FAR '14YEARS_C_CPP_JAVA_MATLAB'

ImLeftFooted
Quote:

Am I the only one who hasn't had problems with pointers and memory management?

I haven't. I find it kind of fun to control my own memory allocation

Tobias Dammers
Quote:

However, I think English is the best language.

Nah. It doesn't even have consistent spelling.

Quote:

I usually prefer to program in HTML.

No you don't. HTML is a markup language, it has nothing to do with programming. Various extensions and embedded applets can provide programming abilities, but pure HTML has nothing to do with programming. Look up 'Turing complete' in Wikipedia and you'll get a clue.

C++ is teh workhorse, though I wish it had some of the features Java has (not GC though, but the serialization stuff is nice, convenient abstracted cross-platform access to all sorts of hardware, web and database integration), and that C++ weren't so explicit. Quite some extra typing required only for historic reasons (e.g. header guards).
Java, IMO, is just a bit too bloated to be acceptable. Having the JRE running in the background and eating precious system resources (not all machines are quad-core 6 GHz with 64 GB RAM) isn't nice. And we'll all use intel processors soon anyway, so why the fuss about cross-platform compatibility...

Karadoc ~~
Evert said:

Am I the only one who hasn't had problems with pointers and memory management?
I probably had some difficulty the first time I tried to use them (in Pascal), but I've never had a problem in C (or C++).

I'm sure there are lots of non-programmers who have never had those sort of problems with C. :P
For me, C is favourite language. I'm a bit fan of the pointers, and I feel like C really puts me in control of the computer. I like the philosophy that "the programmer knows what they are doing", and so the language should just do what you tell it to do.
Once upon a time I did have a bit of a nightmarish memory bug in one of my games; but never again since then. I know how to avoid those problems now, and I know what the symptoms are as well.

Jonny Cook said:

I usually prefer to program in HTML.

I like variables much better than HTML.

axilmar
Quote:

Am I the only one who hasn't had problems with pointers and memory management?
I probably had some difficulty the first time I tried to use them (in Pascal), but I've never had a problem in C (or C++).

It depends on the project's complexity and the rate of changes. For personal projects, that are usually small, I usually do not have a problem. But when KLOC is large, the chances of having a memory problem increases exponentially.

Jonny Cook

Yeah, that was supposed to be a joke. I was hoping it sounded ridiculous enough that it was obvious... guess no. :-/

Quote:

I like variables much better than HTML.

As do I, although I'm sure you could rig something up in HTML that's somewhat variableish.

[edit]
Oh, and I actually prefer C++... just so people can take me seriously again. :(

Karadoc ~~
axilmar said:

the chances of having a memory problem increases exponentially

increases exponentially with what? The size of the program? I don't think so.
To get zero memory errors you just need to not make any memory related mistakes in each line of code. Since you can do this on a line by line basis, the chances of getting a memory error must increase linearly with the size of the program.

Matt Kindy
Karadoc~ said:

ince you can do this on a line by line basis, the chances of getting a memory error must increase linearly with the size of the program.

That's not neccesarily true, you see. For example you can make two memory errors in a line, or, with a loop, you can have one memory error over, and over again, which is basically more than just one error. Also, you could have a line that doesn't deal with memory, therefore, it could end up looking like this:


{"name":"589614","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/9\/b9d33ab751bc75688c3afdd96c6c2803.jpg","w":400,"h":400,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/9\/b9d33ab751bc75688c3afdd96c6c2803"}589614

Instead of this:

{"name":"589613","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/d\/2d685d0416531eb3d6454af382d3ed68.jpg","w":400,"h":400,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/2\/d\/2d685d0416531eb3d6454af382d3ed68"}589613

Evert
Quote:

That's not neccesarily true, you see. For example you can make two memory errors in a line, or, with a loop, you can have one memory error over, and over again, which is basically more than just one error.

That's nonsense. It's one error, regardless of how often the code is executed.
Anyway, I think you missed the point of Karadoc~'s line of reasoning, which deals with averages over a large number of lines in code (let's be honest: how many implementations of Hello World have you seen that have a memory leak?)
Anyway,

Quote:

the chances of getting a memory error must increase linearly with the size of the program.

I'm not sure I agree: in a complex programme, you can have correlations between lines that lead to memory leaks even if each line by itself looks fine. Therefor, I would expect the chance to scale quadratically with the number of lines of sourcecode.

There has to be a way to test this experimentally. Problem is that it requires people to write a statistically significant number of programmes (so we can compare different source sizes) of different length, of similar levels of complexity, without them fixing accidental memory leaks along the way. Probably not doable, and as we're arguing over a hyperbole, also not worth the effort.
But it's a fun idea.

Matt Kindy

That makes sense :o

Goalie Ca

A while back i discovered the boost programming libraries for C++. While i wish the language had more features built in (kudos to C# for having an awesome language but horrible windows libraries).

I've been using boost smart pointers, ublas, etc. In fact some of the boost code will end up in the next standard for c++. Smart pointers though are basically good reference counters but there are several kinds for each purpose and add very little overhead. Of course the nice thing about boost is that it is very well written and adds very little overhead.

http://www.boost.org/libs/smart_ptr/smart_ptr.htm
http://www.boost.org/doc/html/array.html //fast but only for static sizes.
http://www.boost.org/libs/libraries.htm //list of everything

Matthew Leverton

I think the people who are saying that memory management isn't a big problem are either a few of the world's best programmers or have never worked for multiple years on a large project with a group of other programmers with varying levels of talent. Almost every single remote security vulnerability is due to bad memory management with programs written in C. These aren't just isolated cases of a few bad programmers.

Memory management sucks and if you are bitten by it, you might just be spending a few days trying to trace it down. Especially if you have to work through someone else's messy code... In a corporate world, that translates to lots of lost money. After enough of those problems, it becomes cheaper to buy better hardware to run the (slower) higher level languages. The longer I program, the more I appreciate high level languages. It's not that I don't understand how to access memory, it's just that it's a waste of my time.

About the only place I think C or C++ belongs is in DLLs that provide speed critical methods for a higher level language to access. Also, there are some applications (like most Allegro games) that don't require a lot of complex memory access that are still a good fit for C/C++.

23yrold3yrold

I can appreciate that, and maybe my mind will change if I ever work for a big company on this stuff. For the most part though, on projects like most of us do, a little preplanning and your program should manage the memory just fine.

Goalie Ca
Quote:

or have never worked for multiple years on a large project with a group of other programmers with varying levels of talen

Well I must add that there are tons of different types of programming. I didn't want to say this but "the right tool for the job" needs to be mentioned. For the work i do, managed code simply won't cut it and isn't even necessary.

That said i would love to see more managed interfaces to game libraries. Managed Directx looks nice and so does Tao. I'm sure the allegro .net interfaces are nice indeed. Personally i wouldn't be surprised if in 10-15 years we don't see managed code as part of the big titles just because development time is short and games are becoming far more complex. The runtimes are becoming very efficient as well. Plus, since we're all talking about making parallel code for multi-cores and the rest it would be nice to make use of built-in language features rather than calling sem_lock and the rest.

It would be neat to see runtimes take a look at the hardware its running on, ie: number of cpu's, ram, etc. and compile it just for that system.

Matthew Leverton
Quote:

I didn't want to say this but "the right tool for the job" needs to be mentioned.

That's what I mean when I say that there are programs "that don't require a lot of complex memory access that are still a good fit for C/C++." Usually where memory access comes to bite you is when you are dealing with arbitrary input from (untrusted) users. If you're not working in that realm, then a lot of your memory bugs may simply go safely unnoticed.

Working with C makes me feel like I know what I'm doing and what's going on, but I don't get a "rush" from that anymore. Assuming that the program runs "fast enough," I'd rather just get the job over as quickly as possible.

Goalie Ca

Heh i totally agree i don't get a rush from coding at all, i get my fix solving problems and making it work. Worrying about things other than the problem at hand really sucks.

Another really nice thing about bytecode and the rest is the virtualization that comes from it. For anyone who's dealt with large systems, servers, multi-users, etc. virtualization is a godsend. Xen is actually a really cool way to run servers.

Karadoc ~~
Evert said:

I'm not sure I agree: in a complex programme, you can have correlations between lines that lead to memory leaks even if each line by itself looks fine. Therefor, I would expect the chance to scale quadratically with the number of lines of sourcecode.

Yeah, in the back of my mind while I was writing the 'linear' thing I was wondering about memory errors caused by combinations of lines rather than just one erroneous line. But I kind of swept the idea under the carpet by imagining that we are programming in a nice and modular fashion. I reckon that whenever there is a memory leak, it is due to just one erroneous section of code. Either bad programming in one of our modules, or bad use of a module. I guess there could be examples in which it isn't really like this, but I think they will be rare. I truly believe that the probability of an error would scale approximately linearly**. However, when you do have a memory error, the difficulty of finding and correcting it probably increases exponentially.

Fortunately, those of us who are scared of memory errors can use memory management stuff in C++ (and not have to resort to an awful language like Java :P).

(** something just occurred to me while I was writing that. If the probability of having a memory error scales linearly, that means there will be a program size for which you are certain to have an error... That doesn't sound right.)

Goalie Ca

I'd guess that the probability of a memory leak or other memory errors would increase wrt how the object/pointers are being passed around. The nice thing about smart pointers is that when the pointer goes out of scope or does anything else then the count changes. Garbage collection effectively does the same thing but then again only full blown gc's like java's can deal with cases like circular references.

As for buffer overflows you can easily avoid things like that by using classes to manage and perform the checks automatically. This includes string classes, array classes, etc. C++ can throw/catch exceptions but i hardly see anyone use them!

The problem with C++ is that none of these features are standard anywhere. Someone has to take the time and develop a 3rd party library and people actually have to adopt it. It is a pain in the ass when every library has its own way of dealing with this and none of it interoperates. Even so, "best coding practices" are needed. You still have to take more care than you do with java for instance. But on the flip side if you are writting a large application you need to know exactly how the gc behaves to ensure things go smoothly. GC does not come free by any means.

Jonatan Hedborg

It is of course not impossible to write perfect, memory-error free code. The problem is that you have to! There is a lot of effort put into making those destructors, deletes, making sure there are no dangling pointers and what-not. With a GC'ed language like java, you dont have to think about it.
Oh, and java also has the advantage of having built-in thread support. The only thing i really miss in java is operator overloading... :(

nonnus29
Quote:

It's not that I don't understand how to access memory, it's just that it's a waste of my time.

That's the point exactly. ;)

ImLeftFooted
Quote:

There is a lot of effort put into making those destructors, deletes, making sure there are no dangling pointers and what-not.

For you, yes.

Different people have different tastes in languages. To me there isnt much effort for doing dtors, deletes and making sure there are no dangling pointers. Its about a 2-5 second decision for me while I'm designing a given compilation unit.

Some people think of classes / OOP as a lot of effort with no real benefit. To each his own.

Jonatan Hedborg
Quote:

Some people think of classes / OOP as a lot of effort with no real benefit. To each his own.

What does that have to do with anything? What i'm saying is that regardless of how much/little time you spend doing your dtors etc, you still spend that time doing that - time you could spend on something else.

Arthur Kalliokoski
Quote:

Usually where memory access comes to bite you is when you are dealing with arbitrary input from (untrusted) users.

Hmmm.... lemme think <thumps head> Linux kernel is C and asm. Windows is thought to be largely C++. Which one has the buffer overruns again?

Matthew Leverton

You are comparing a kernel to the entire Windows platform?

ImLeftFooted
Quote:

What does that have to do with anything? What i'm saying is that regardless of how much/little time you spend doing your dtors etc, you still spend that time doing that - time you could spend on something else.

Maybe it would be worth it for you to program in ASM? less time spent writting useless semicolons and paraenthesis. What i'm saying is that regardless of how much/little time you spend doing your semi colons, parenthesis, etc, you still spend that time doing that - time you could spend on something else.

Kitty Cat

It doesn't matter how "efficient" a language is if the person using it isn't good with it. The efficiency will be lost. Besides, constructors and things actually do something, so it's not like you're wasting time.

Shawn Hargreaves
Quote:

You are comparing a kernel to the entire Windows platform?

Very true. The Windows kernel is almost entirely asm, too. C++ isn't even officially supported for anything that runs in kernel space! (eg. device drivers), although a lot of third party drivers do actually get written in C++.

And, the Windows kernel isn't where the buffer overruns happen. Applications are a whole different kettle of fish.

On the issue of manual memory management, the real problem comes when you try to reuse code. For a small one person project it is totally possible to do manual memory management and get it 100% correct, but that just doesn't scale. As soon as you have more than one developer working on a codebase, or you want to package up some function as a reusable library, you run into a whole bunch of problems:

  • When a function returns a buffer, who allocates that object?

  • Who is responsible for freeing it?

  • If the caller allocates it, how do they know how big it needs to be?

  • If the callee allocates and frees it, what sort of interface do they expose for that?

  • If the callee allocates and then the caller frees, how do you make sure they are both using the same underlying memory management API?

  • What happens if several different clients are sharing the object?

  • What if the object has internal implementation state that prevents it being freed at the time the caller thinks it should?

These sort of questions are trivial to answer in any given case, but they pile up exponentially as the project complexity increases. I can expose an API and tell my coworker how to use it, that's no problem. But then my coworker wants to use my type as a return value from some other API that he is exposing for someone else, and they're using this alongside a component written by a different group, which had a load of legacy code that doesn't fit out latest conventions, and they're also using a couple of third party libraries that they don't control at all. All of a sudden there can be literally hundreds of different memory ownership patterns in use at the same time in the same program, perhaps straddling DLL boundaries to make things even more awkward, and nobody can fit all this in their head at once to make sure it is all correct.

I've only ever seen three techniques that can actually make large scale C++ memory management work correctly:

  • Just don't do it. Allocate a bunch of static buffers up front, then don't allocate or free anything while the program is running. A lot of console games do this, but it isn't really practical for the majority of software.


  • Just don't do it version 2. Make everything a value type instead, and put them on the stack. Or have a very small number of rigorously tested container types, and store value types inside them. This is the STL approach. Works fine, but not super efficient because you end up with a lot of copy-by-value of large objects.


  • Use reference counted smart pointers. This is where most big C++ apps seem to end up, perhaps in combination with lots of STL style value types. Again it works, but managing all those reference counts adds a lot of overhead (not to the programmer if they use a smart pointer wrapper class, but at runtime it slows your app down more than is ideal).

The thing about reference counted smart pointers is, really this is just a bad form of garbage collection! In a true GC environment, things work just the same as if you had reference counts, but it runs faster because the GC can be optimised to only do periodic sweeps, use generations, work in a background thread, and only kick in after there has been a lot of allocation activity, where reference counts need to be updated every time you transfer ownership of an object (ie. all the time while code is running).

So I think GC is a very very good thing indeed. It works better, and is faster, than any of the other options.

Quote:

Yeah, in the back of my mind while I was writing the 'linear' thing I was wondering about memory errors caused by combinations of lines rather than just one erroneous line. But I kind of swept the idea under the carpet by imagining that we are programming in a nice and modular fashion. I reckon that whenever there is a memory leak, it is due to just one erroneous section of code

I think it's the exact opposite: almost all errors happen in the gaps between modules.

// EngineInfrastructure.dll
Wibble *CreateWhatsit(Flibble *params)
{
    return new Wibble(params);
}

// MyGame.exe
void FlobTheWhatsit(Flibble *params)
{
    Wibble *wibble = CreateWhatsit(params);
    wibble->Flob();
    delete wibble;
}

Do you see the memory leak?

No?

There might not be one.

A lot depends on the guy who wrote the Wibble type, which is coming from some third source. So in reviewing this code to make sure it is all ok, I (who am just writing the MyGame.exe: I got the Wibble class and EngineInfrastructure.dll from a coworker), have to go and look at the implementation of Wibble to check if it does actually have a destructor, or if there's some other Cleanup() method I might be supposed to call instead. This slows me down, wastes time, and might introduce a bug if I forget to check.

Ok, so let's suppose we have coding guidelines that say all types must have destructors. What if Wibble came from a third party that didn't follow our guidelines? I might not know that and would just assume it was ok. There's a bug right there.

Or lets suppose Wibble is actually fine. There still could be a memory leak depending on how EngineInfrastructure.dll and MyGame.exe are compiled. Lets say we always build EngineInfrastructure.dll in release mode, to make it nice and fast, but I'm doing a debug build of MyGame.exe. That's probably going to leak because the memory is getting allocated by one version of the runtime libraries, then freed by a different version from a different DLL. But you can't spot that from a code review: you have to know a lot about the compiler and look in the build scripts to even spot the problem.

Which is why garbage collection is a Good Thing.

I never ever want to write anything with manual memory management ever again. I have better and more interesting problems to spend my time on!

axilmar
Matthew Leverton said:

I think the people who are saying that ...

Well said. As a programmer many times bitten by C++, I fully agree.

Shawn Hargreaves said:

On the issue of manual memory management, the real problem comes ...

Wise words.

Both your comments fit right with my personal experience. I guess the problems are not a coincidence.

I had an exchange of rough words over artima.com over this. I am a full supporter of C++ getting optional garbage collection in the standard, but some people think it is not needed. It's truly amazing, in a negative way, that people support the view that C++ does not need garbage collection...including the C++ standards committee and Bjarne Stroustrup himself. When these people realize their mistake, it would be too late for C++.

ImLeftFooted
Shawn Hargreaves said:

Which is why garbage collection is a Good Thing.

Wow that makes a crap load of sense. I think you've convinced me to like GC.

axilmar said:

It's truly amazing, in a negative way, that people support the view that C++ does not need garbage collection...including the C++ standards committee and Bjarne Stroustrup himself. When these people realize their mistake, it would be too late for C++.

Maybe the solution is to implement your own GC in C++. C++ lets you override the new operator and such, which is probably why Stroustrup doesnt want C++ to force a GC, he just wants to leave the option.

Marcello

D? :D

Marcello

Goalie Ca

I remember reading about C++0x (the next official version) a while back and i dug it up again thanks to google.

It's an interesting read but i feel it covers some areas well but falls short in many others. Read about it and you'll see what i mean.
http://www.artima.com/cppsource/cpp0x.html

edit:
del.icio.us also came up with this interesting piece by bj
http://www.informit.com/content/images/art_stroustrup_2005/elementLinks/rules.pdf

edit2:
Found an interesting "wishlist" page on writely. http://www.writely.com/Doc.aspx?id=bchdmtqvpnxv4

Marcello

wow that looks horrific. why not lead dead horses die?

Evert

Let me begin by clarifying something from my last post: I disagree that using dynamic memory in C or C++ automatically means your program starts getting memory errors or starts crashing. It goes without saying that not having memory to manage means less work.

Wether or not a garbage collector is a good thing or not will depend on what your programme is used for. If I'm writing a game or GUI application, I probably don't care either way (I do those by myself anyway). If I'm writing something to do numerical work, I sure as hell don't want a garbage collector running in the background. That's not to say that I wouldn't be allocating and deallocating large chunks of memory in the time critical part of the code anyway.

Quote:

why not lead dead horses die?

Why do people invest time in making FORTRAN 2003?

Trezker

Memory management is were the fun stuff happens. It's the magical place where wonderous bugs appear at random at the worst possible time.

DICE told us a story about saving money. One of their programmers thought that they were spending an awful lot of time testrunning the program to see if the latest compile was still running as it should.
He sat down and did the math. Then he went to his bosses and told them they should buy a dozen new monstercomputers. Ofcourse the bosses were sceptic saying that was very expensive. But since the programmer had done the math, he could show them that the cost of getting those computers would be earned back within just a week.

All those computers are currently working day and night automatically running the latest builds and reporting when shit hits the fan.

Carrus85

Personally, I think garbage collection shouldn't be integrated as a language feature in C++ (ala java where all objects are put onto the heap automatically and garbage collected whenever the gc feels like it), it should be more along the lines of a standard library module. (ala auto_ptr<type>, only something like gc_ptr<type>).

The main problem with global garbage collection is that with RAII, you want the destructors to be executed when the object is no longer of use (otherwise mutexes, files, network connections, etc. won't be properly released); unfortunately, there is really no way to call the destructor independantly from the memory allocation/deallocation code (short of overloading the delete operator for an object and using some pooled memory allocation scheme). They could hack the destructor mechanism to do nothing more than execute the destructor code and put the memory into a list to be released later, but then you are shooting the people who want the memory free NOW in the foot. Of course, you can do this exact thing on a case by case basis by overloading the delete operator, but then we are getting back into the realm of "standard library module" again.

I agree, a standardized garbage collection scheme would be nice. However, they shouldn't force it on those who desire not to use the GC.

Goalie Ca
Quote:

However, they shouldn't force it on those who desire not to use the GC.

Doing that would go agains the fundamental principal of C++ being that if you don't want to use it, it shouldn't cost you anything. Embedded/Real time systems programmers would cry fowl. This is why if they add it, it WILL be OPTIONAL. There will be smart pointers for everyone else if they want of you can probably go back to using new/delete/malloc/your own allocator schemes.

axilmar
Quote:

Maybe the solution is to implement your own GC in C++. C++ lets you override the new operator and such,

I have tried...I made several versions, from totally specific to Win32 using every available trick they offer, right down to the most generic portable ones. None of them really worked, as it is not possible to do it without language support.

I even submitted one to boost: boost vault

There are numerous problems:

1) if the newly created object is registered in a global list of objects and a collection is done before operator new returns, the new object will be collected.

2) there is no way to know where pointers are in objects, in stack frames and in global data. There are many tricks that can be done, but they all slow down an application unnecessarily.

3) you can not guarrantee that an object will always be allocated on the heap. In C++, an object could be on the stack. Thus operator new is not invoked in this case. How do you know when an object is on the stack or on the heap? Again, there are many tricks for that, but the performance is horrible.

Quote:

which is probably why Stroustrup doesnt want C++ to force a GC, he just wants to leave the option.

My thoughts are exactly that: GC must be optional. In C++, you don't have to pay for what you don't use. But what I need is language support for it. Without language support, it is not really possible.

Quote:

D?

D enforces all objects on the heap. Not good, in my opinion.

Quote:

Wether or not a garbage collector is a good thing or not will depend on what your programme is used for. If I'm writing a game or GUI application, I probably don't care either way (I do those by myself anyway). If I'm writing something to do numerical work, I sure as hell don't want a garbage collector running in the background. That's not to say that I wouldn't be allocating and deallocating large chunks of memory in the time critical part of the code anyway.

Exactly. That's why it should be optional. But it should be there nevertheless.

Quote:

Personally, I think garbage collection shouldn't be integrated as a language feature in C++ (ala java where all objects are put onto the heap automatically and garbage collected whenever the gc feels like it), it should be more along the lines of a standard library module. (ala auto_ptr<type>, only something like gc_ptr<type>).

It is not possible to do that. A gc_ptr can be:

1) part of the global data.
2) part of the stack.
3) part of a heap object.
4) part of a stack object.

How do you know where is your pointer? there is no way to know that.

Furthermore, you need to register a root gc_ptr in a global list. Which means that for every declaration, you need to lock a mutex in a multithreaded environment. And that means severely crippled performance.

An optimization of this is to use a thread-local-storage list. But then you have to access the TSS segment.

Then there is the problem of removing a pointer from the root set. How do you do that? the obvious answer is 'in the destructor'. But how do you know if your pointer is a root one? you have to keep that information from the constructor.

The analysis so far shows the following possible solution (a solution that I have provided in the boost submission):

class gc_ptr {
    gc_ptr() {
        is_root = magical_function_to_know_if_a_pointer_is_root(this);
        if (is_root) add_root_ptr(this);
    }

    ~gc_ptr() {
        if (is_root) remove_root_ptr(this);
    }

    void *ptr;
    bool is_root;
}

The above is totally slow if you use STL, because removing an object from a list with thousands of objects will bring your app to the halt.

One way to improve this is to use a map of pointer addresses. But then it is again very slow (I've tried it - the improvement is large, but again the app is very slow).

Another way is to keep the iterator in the pointer, so as that the removal takes constant time. The class becomes:

class gc_ptr {
    gc_ptr() {
        is_root = magical_function_to_know_if_a_pointer_is_root(this);
        if (is_root) it = add_root_ptr(this);
    }

    ~gc_ptr() {
        if (is_root) remove_root_ptr(it);
    }

    void *ptr;
    bool is_root;
    list<gc_ptr *>::iterator it;
}

But then look at the memory consumption! a pointer jumps from 4 bytes to 12 bytes on 32-bit machines. On big PCs it probably does not matter, but on smaller machines (PDAs, cell phones, controllers), it is not an option.

Quote:

The main problem with global garbage collection is that with RAII, you want the destructors to be executed when the object is no longer of use (otherwise mutexes, files, network connections, etc. won't be properly released); unfortunately, there is really no way to call the destructor independantly from the memory allocation/deallocation code (short of overloading the delete operator for an object and using some pooled memory allocation scheme). They could hack the destructor mechanism to do nothing more than execute the destructor code and put the memory into a list to be released later, but then you are shooting the people who want the memory free NOW in the foot. Of course, you can do this exact thing on a case by case basis by overloading the delete operator, but then we are getting back into the realm of "standard library module" again.

No, RAII is not a problem with GC in C++. Objects that are to be used in a RAII fashion are to be allocated on the stack, so there is no problem. That's why I like C++, and RAII especially, because it solves so many problems. And that is one of the reasons that I do not want to abandon C++.

EDIT:

There are other problems as well with a library implementation.

1) arrays of objects. In C++, one can not only allocate arrays of object pointers, but arrays of objects themselves. While this is efficient, there is no standardized way to walk an array of objects.

2) array of pointers. In C++, you can allocate an array of pointers on the heap/stack. A pointer inside an array does not need to register/unregister itself. You do not know if a pointer is part of an array or not in stack allocation.

What is the solution for all this? the solution is either that the C++ standard offers standardized support for GC or it offers a powerful reflection/introspection/metaprogramming facility that allows GC to be an add on.

What is needed for truly efficient precise garbage collection is to:

1) create a mark procedure for global data.
2) create different mark procedures for each object.
3) create different mark procedures for each stack frame.
4) link stack frames procedures on the stack, as functions are entered.
5) unlink stack frames procedures on the stack, as functions are exited.
6) provide an API for walking the CPU's registers.
7) provide an API for suspending / resuming threads.

The algorithm for collection then becomes trivial:

if allocated memory > allocated limit then
    suspend all threads
    mark global data
    for each thread
        invoke mark procedures of stack frames
        mark CPU context of thread
    end for
    for each GC block
        if block is not reached then
            remove block from list
            finalize block
        end if
    end for
    resume all threads

That's the easiest case, i.e. mark & sweep. The other cases that use copying are also very easy to implement, although not that trivial.

Adding garbage collection to C++ will open a vast new opportunity for C++ in the business sector. Stack-based allocation is too important a feature to leave it out, in performance and correctness. It will also allow many new frameworks to be written for C++ in domains that C++ is severely lacking.

Goalie Ca

axilmar, you seem to be quite knowledgeable AND experienced in this matter so i have a few (sorta) questions...

0) Did you use the conservative Boehm gc model? It seems to be "the method" but how does it compare to others?

1) Pointer hiding... in c++ you can do all kinds of things to confuse the GC because of pointers. Even at the language level this remains a problem. How could this best be resolved?

2) Dealing with "unmanaged" resources. C# has several mechanisms in dealing with unmanaged resources. It solves the problem by adding keywords and metadata basically saying "don't touch me!" and then it is assume the programmer will appropriately release it in the destructor or finalize (finalize is an interesting concept in and of itself!). Basically we end up having to do things the old way.

3) Threading... each system has a different threading models from basically lightweight processes to userspace threading. From what i understand when a GC collects all threads are stopped and then the business is done. Different systems will of course have different behaviour and performance hit is always an issue but seems like it would be larger on more parallel systems. It would also be wise to check if a collection is pending (this is highly recommended in c#) before doing certain things. Sometimes a thread will be manually blocked until after the gc.

4) Generations... perhaps this is just an implementation issue but i noticed that with C# if i made it to the 2nd generation (it uses 0,1,2) collection was often missed (took forever) as it was thought that checking 0 was good enough. Things were moved and "compacted to make room" in the lower generations instead and grouped with their own generations. Large objects are on the large object heap entirely seperate from the regular one. This less than ideal hack seems to work for a lot of cases though

5) Finding memory leaks. This would be a useful method for finding memory leaks if an appropriate api was available and accessible. Then the program could revert to one without GC. Can the gc be made to simply monitor and allow the standard new and delete? This brings me to an unrelated question. Is it desirable/possible to be able to explicitly force deletion of a specific object "right away" if its no longer being referenced.

axilmar
Quote:

Did you use the conservative Boehm gc model? It seems to be "the method" but how does it compare to others?

No, my method is different. Here are the differences:

1) my collector is precise. It scans only pointer classes and uses various tricks in constructors, destructors and operators new/delete to find where pointers are. Boehm's collector is not precise: it scans all the data of a stack, globals and heap, and it uses various heuristics to find pointers.

2) my collector uses the global operator new and delete to allocate and delete data. The Boehm's collector uses a custom allocator which plays with the page file.

3) my collector is 'mark&sweep', whereas Boehm's collector can be configured to use copying.

4) since my collector uses C++ and pthreads, it does not stop the world, but it blocks on mutexes (a separate mutex for each thread). Therefore, as long as a thread does not use GC, it runs without being stopped. I haven't tested it fully though, due to lack of time. Boehm's collector can be 'stop the world' or incremental.

5) my collector has weak pointers! I consider weak pointers as necessary in any garbage collection system, because it allows listeners to be disconnected from models automatically. I do not think it is possible to make weak pointers with Boehm's collector (although my understanding is not that good in this).

The Boehm's collector is a very proffesional work that spans more then 20,000 lines of code which dips in very low levels of each operating system that it runs on. It is also a work of many people over many years.

But it still requires effort from the programmer in order to be fast (you have to declare the mark routines yourself), and it still does not solve the problem of accurately tracking pointers.

Quote:

1) Pointer hiding... in c++ you can do all kinds of things to confuse the GC because of pointers. Even at the language level this remains a problem. How could this best be resolved?

You can view the problem from two sides:

a) pointer hiding should not be allowed within a GC context.

b) it does not matter as long as there is at least one other non-hidden strong pointer to an object that keeps it for being collected.

Quote:

2) Dealing with "unmanaged" resources. C# has several mechanisms in dealing with unmanaged resources. It solves the problem by adding keywords and metadata basically saying "don't touch me!" and then it is assume the programmer will appropriately release it in the destructor or finalize (finalize is an interesting concept in and of itself!). Basically we end up having to do things the old way.

RAII is your friend here. By coding the appropriate RAII classes, there shouldn't be any problem. For example, closing a handle could be automated by a RAII class that closes handles at its destructor.

Quote:

3) Threading... each system has a different threading models from basically lightweight processes to userspace threading. From what i understand when a GC collects all threads are stopped and then the business is done. Different systems will of course have different behaviour and performance hit is always an issue but seems like it would be larger on more parallel systems. It would also be wise to check if a collection is pending (this is highly recommended in c#) before doing certain things. Sometimes a thread will be manually blocked until after the gc.

Indeed, but from the language perspective, all that it has to be done is

a) declare which procedure is a thread.
b) declare a suspend/resume mechanism for the thread.

Then it does not matter what threading model is used. The compiler could use the information declared by the programmer to properly suspend/resume threads.

For example:

1//one type of thread
2thread {
3 void myproc() {
4 handle = getUserlevelThreadHandle();
5 bla bla user code
6 }
7handle {
8 pthread_t handle;
9}
10suspend {
11 suspendUserlevelThread(handle);
12}
13resume {
14 resumeUserlevelThread(handle);
15}
16 
17//another type of thread
18thread {
19 DWORD myproc(LPVOID lpParams) {
20 handle = GetCurrentThreadHandle();
21 bla bla user code
22 }
23handle {
24 HANDLE handle;
25}
26suspend {
27 SuspendThread(handle);
28}
29resume {
30 ResumeThread(handle);
31}

The proposal adopts a block structure like a try-catch-finally block. There can be many solutions to this; imagination is only the limit.

Quote:

4) Generations... perhaps this is just an implementation issue but i noticed that with C# if i made it to the 2nd generation (it uses 0,1,2) collection was often missed (took forever) as it was thought that checking 0 was good enough. Things were moved and "compacted to make room" in the lower generations instead and grouped with their own generations. Large objects are on the large object heap entirely seperate from the regular one. This less than ideal hack seems to work for a lot of cases though

You can have generations, but in C++ it is only long-lived objects that are usually allocated on the heap; most, if not all, temporary structures, are allocated on the stack.

Quote:

5) Finding memory leaks. This would be a useful method for finding memory leaks if an appropriate api was available and accessible. Then the program could revert to one without GC. Can the gc be made to simply monitor and allow the standard new and delete?

The Boehm's GC can do that, as well as a number of other frameworks.

Quote:

Is it desirable/possible to be able to explicitly force deletion of a specific object "right away" if its no longer being referenced.

If it is no longer referenced, then why keep it around?

Steve++

I agree with everything Shawn said.

BUT...

Garbage collection has no place in standard C++. As an absolute maximum, there could be optional language support for garbage collected objects, but these objects would be able to do limited things. C++ occupies the systems programming niche. It is used for very large projects at great expense. It is a really big challenge to introduce garbage collection to C++ because objects are managed completely by the programmer and there would need to be some surrender of this control to the runtime system to achieve proper garbage collection.

I've made games and demos in C++ and I've learned a few things. The biggest lesson I've learned is to avoid new and delete at all costs; or at the very most, preallocate large chunks at predetermined intervals, then manage those chunks internally (having done a university topic on operating systems exposed me to memory management algorithms). Frequently allocating and deleting memory not only opens the risk for leaks, but also degrades performance noticably.

Another lesson: Don't be a "don't re-invent the wheel" purist. I like the STL, but it dynamically allocates memory from the heap. This violates the first lesson I've learned. Consequently, a while back I wrote a simple linked list template that allocates dynamically from a preallocated chunk of memory. This gave me a linked list that could be used agressively for managing game objects without fragmenting the memory. The only catch is that preallocating a big chunk can affect the rest of the game if the chunk is too big.

I've found that by creating objects and arrays on the stack as much as possible, memory leaks are a non-issue. Performance loss from passing these objects around is also a non-issue, because they can be passed by reference thanks to &.

Having said all that, choppiness from fragmented memory is less of a problem in GC'd languaged like Java as it does a big sweep periodically and cleans this up. Also, chopiness really kills 2D games (especially scrollers) because scrolling speed needs to be predictable and jerkiness is really noticable. On the other hand, 3D games render frames as soon as the last frame is finished, however long that takes, and they use an unpredictable delta between frames rather than a fixed unit. Users are accustomed to seeing this, so a bit of choppiness is OK.

I haven't given up C++ completely, but as my projects become more complex, I feel the need to use Java to speed up development substantially. Like Matthew et al, I am quite competent with all aspects of manual memory management, but it is now a burdensome chore that I can no longer be bothered doing. Even looking for the appropriate boost libraries is too much work.

Java is an excellent tool for gamedev, especially large projects with large teams.

Evert
Quote:

The biggest lesson I've learned is to avoid new and delete at all costs;

Not an option if you have a large amount of data to handle and don't want to make it a global variable.

Quote:

preallocate large chunks at predetermined intervals, then manage those chunks internally

Of course. Allocating and deallocating chunks of memory on the fly is a performance killer.

Goalie Ca
Quote:

You can have generations, but in C++ it is only long-lived objects that are usually allocated on the heap; most, if not all, temporary structures, are allocated on the stack.

From my understanding in languages like c# and java anything using new goes on the heap (so pretty much every object in existance). In c++ i understand that it is pretty much the same deal. But the question i have is with the stack. What is the process of deconstruction for it. I assume that as elements go out of scope (at the end of curly braces) it's marked at clean and alls well. But lets say someone has a pointer to it in some other function and holds on to it forever and ever. I'm assuming at some point it is possible for the stack to shrink below that entry and even grow up to it again in the meanwhile. Without a GC would that object go out of scope? (i'm assuming yes) and with a GC it probably wouldn't be collected no?

There were a few comments about avoiding "new" and "delete" because of speed. Allocating memory in an inner loop is not something sane people do but perhaps for something like a webserver memory will be allocated/deallocated many times a second. For a second lets assume that the apache/whatever coders do not recycle memory. Could there be a potential performance gain from the garbage collector itself doing all the recycling automatically. That would surely avoid the costly system calls.

Carrus85

I wouldn't be surprized if apache/whatever coders would end up using a memory pool, so all of the required memory is allocated only once, and freed only once. Just overload the new/delete operators to ask/return memory from/to the pool instead of from/to the operating system, and you have effectively avoided the overhead of malloc/free (which is where the speed hit for new/delete comes from) for every object you have created. Of course, if you don't create a crapload of a particular object on the heap, you will probably not see that much benefit from this approach...

axilmar
Steve++ said:

Garbage collection has no place in standard C++.

I keep hearing the same thing over and over, that C++ is a system's programming language and it should not have garbage collection etc. Why shouldn't it be optional?

Quote:

As an absolute maximum, there could be optional language support for garbage collected objects, but these objects would be able to do limited things.

Why limited things? there is no problem in having GC whatsoever. I do not see the reason to limit anything.

Quote:

C++ occupies the systems programming niche.

It depends on the definition of system. C++ is certainly not used for kernels. But it is used for drivers and libraries.

For me, the word 'system software' is synonymous to really lowlevel code, i.e. kernels, microcontrollers etc). A GUI library, a database, etc are certainly not system software...and most major libraries are not system software as well (boost for example, or Qt, or MFC etc).

That C++ is a system's language is largely a myth, but having optional GC does not exclude C++ from being used in situations where lowlevel code is needed.

Quote:

It is used for very large projects at great expense.

That's why GC is needed.

Quote:

It is a really big challenge to introduce garbage collection to C++ because objects are managed completely by the programmer and there would need to be some surrender of this control to the runtime system to achieve proper garbage collection.

No, there would be no need to surrender any runtime control to achieve proper garbage collection. Take the Boehm's collector, for example: it can be used in C and C++ programs without any problem. The real problem with Boehm's collector is that it is not a precise collector, unless the programmer makes a huge effort to write specific mark routines for each object.

Quote:

Frequently allocating and deleting memory not only opens the risk for leaks,

That's another myth. I have done apps where frequent allocation/deletion is a must. But the risk of leaks did not increase.

The possibility of leaks is a function of complexity, not allocation frequency.

Quote:

but also degrades performance noticably.

Indeed. Copying GC allocation is much faster, because it takes linear time.

Quote:

I haven't given up C++ completely, but as my projects become more complex, I feel the need to use Java to speed up development substantially. Like Matthew et al, I am quite competent with all aspects of manual memory management, but it is now a burdensome chore that I can no longer be bothered doing. Even looking for the appropriate boost libraries is too much work.

Java is an excellent tool for gamedev, especially large projects with large teams.

You wouldn't have to use another line of tools if C++ had garbage collection.

Goalie Ca said:

I assume that as elements go out of scope (at the end of curly braces) it's marked at clean and alls well.

Yeap.

Quote:

But lets say someone has a pointer to it in some other function and holds on to it forever and ever.

That's a problem that exists now, but I haven't seen many cases where it is a problem. Usually it is pretty clear from an API's structure and documentation what parameters functions accept.

Quote:

I'm assuming at some point it is possible for the stack to shrink below that entry and even grow up to it again in the meanwhile. Without a GC would that object go out of scope? (i'm assuming yes) and with a GC it probably wouldn't be collected no?

Stack objects are not collectable from a GC.

Steve++
Quote:

But lets say someone has a pointer to it in some other function and holds on to it forever and ever.

This is another reason why I'm liking C++ less. Sure, it stops (or warns) you from returning a pointer to a local object from a function/method, but it doesn't stop things like this:

Square* p;
{
   Square s;
   p = &s;
}
p->display(screen);

The designers of Java must have realised that one of the implications of a having a good garbage collector is that the benefit of stack allocated objects over heap allocated objects would be marginal compared to a non-gc language like C++. On this basis - and for simplicity - they would have decided not to have stack-allocated objects.

axilmar
Quote:

The designers of Java must have realised that one of the implications of a having a good garbage collector is that the benefit of stack allocated objects over heap allocated objects would be marginal compared to a non-gc language like C++. On this basis - and for simplicity - they would have decided not to have stack-allocated objects.

The benefits of stack-based objects are anything but marginal. Let me give you a real world example: an openGL display using gl4java. Each GL object has an integer id. In order to do anything with GL objects, you have to keep a map of object ids to java instances. Each time there is an interaction between objects or between the external world and the display, you have to allocate a new Integer object to pass to the map in order to find the appropriate Java instance. That is a tremendous waste of resources that stack-based allocation would easily solve.

Bjarne Stroustrup has correctly identified the importance of stack-based allocation. On the other hand, he has completely ignored any calls for adding GC to C++.

Marcello

I have to completely disagree with you axilmar.

For example, gl4java is a native library, and hardly recommended for production stuff. I am not sure why you are using it (the fact that it needs integer ids like that is just poor design). In Java 1.5 you do not need to create new Integer objects, as it's all transparent in the language. It does not create a new Integer object for each cast, but instead uses Integer.valueOf which has a bit more intelligent mapping.

That aside, creating stuff on the heap in Java is completely different from C++. Because Java has full control over all pointers and memory, it can do it a lot smarter and reuse memory many times more effectively than you could in C++. The point needs to be understood that it is cheaper to throw more hardware at a problem than to throw more programmers at it. The Java GC/VM is only going to get better, faster, and more efficient, and if you are a java programmer, you do not even have to do any work to get that efficiency. If you are writing in C++, you have to do all the optimization yourself. It's not worth the time for 99% of projects.

Marcello

Steve++
Quote:

Because Java has full control over all pointers and memory, it can do it a lot smarter and reuse memory many times more effectively than you could in C++.

Exactly. The jvm is like an OS in some regards. Games usually allocate a big chunk of memory at the beginning, so it's not a big deal. You can control that size anyway.

Goalie Ca
Quote:

Exactly. The jvm is like an OS in some regards. Games usually allocate a big chunk of memory at the beginning, so it's not a big deal. You can control that size anyway.

With a little language level support wouldn't it be possible to have similar benefits in C++.

Steve++

Why make C++ more like Java? C++ and Java fill different niches. There's some overlap, but they're not fundamentally in competition with each other.

Having said that, I think there's a better option than C++ to fill that particular niche; I haven't found it yet, or it hasn't been invented.

axilmar
Quote:

Why make C++ more like Java? C++ and Java fill different niches. There's some overlap, but they're not fundamentally in competition with each other.

No one suggests to make C++ more like Java. Adding garbage collection to C++ does not make C++ a Java-like language. Lots of languages have garbage collection, so the argument could be "why make C++ more like Smalltalk" for example, which sounds and is silly.

That Java and C++ do not overlap, it is a myth. Java is used for many desktop client apps, just like C++. It is even used in soft real-time apps, like C++ (disclaimer: I work on such apps). Java and C++ are used in mobile apps and embedded controller apps as well.

The only reason Java and C++ do not overlap in some domains is because C++ does not have garbage collection. Put GC in C++, and let's forget Java alltogether.

_Dante

Long time listener, first time caller...

axilmar said:

Put GC in C++, and let's forget Java alltogether.

Nice. Couldn't have put it better myself.

Java and C/C++ absolutely overlap; I make my living doing mobile applications, and as such, am forced to use both languages. The arguments "use the best tool for the job" and "just throw more hardware at it" don't apply.

And as far as the Java promise of "Write Once Run Anywhere" goes, it also does not apply in this space. In fact, as things stand currently, it's quite the opposite - any C++ application I write is 100% binary compatible on all supported handsets, whereas J2ME applications must be re-compiled if they use any of the hardware outside of the CPU and display.

Don't get me started on broken KVM implementations...

Marcello

Garbage collection is hardly the only thing that Java has that makes it easier/better to work with than C++.

The standard Java libraries are far better/easier to use than STL and boost.
Templates in C++ are evil.
C++ has to be compiled separately for each platform (windows/mac/linux/etc.).
Dynamic/reflective coding is near-impossible in C++.
C++ cannot be run in a sandbox/secure "jail".
DLL hell.
bloody. fucking. segmentation faults.

And don't get me started on all the syntactical issues that make C++ such a "pleasure" to work with. There's a lot of repeated code to write classes in C++ (.hpp/.cpp).

Griping aside ;), doesn't managed C++ with .NET or whatever have garbage collection? I've never used that stuff so I'm not sure on the specifics, but that's my only guess as to what the "managed" means.

Marcello

Steve++

There are certainly a lot of good and bad things about C++. If I had my way, I'd ditch the preprocessor altogether. It's a dinosaur. It was only needed when computers were too slow to run compilers that were smart enough not to need them. The template system is also a preprocessor, so get rid of that and introduce real parameterised types. Operator overloading is a good thing, but the implementation in C++ isn't intuitive - have to use 'friend' too often. Stack allocation is good, so I'd probably keep that. Built-in threading support (where available).

I could go on and on... It would be better just to write a new language that takes the best aspects of C++ and Java. D doesn't qualify. I've looked at it a number of times and each time realised why I don't use it. It's got too much ugly syntax. The language itself is a bit bloated.

There's no perfect languages. For me Java is usually good enough and occasionally I use C++ (like the upcoming speedhack).

Shawn Hargreaves
Quote:

Griping aside ;), doesn't managed C++ with .NET or whatever have garbage collection? I've never used that stuff so I'm not sure on the specifics, but that's my only guess as to what the "managed" means.

Absolutely it does: in fact two different versions of it. Anyone interested in adding GC to C++ should take a good look at this, both to see the first failed attempt and then the second version that works rather well.

The original Managed C++ (from .NET 1.1) added a bunch of attributes to indicate which types were garbage collected and which used regular C++ semantics. It worked, but the syntax was incredibly ugly and confusing to use.

As a result, they hired Herb Sutter (very smart guy from the C++ standard committee) to design a better replacement. This new language is called C++/CLI, and ships with .NET 2.0. Instead of using attributes on types, it adds a new symbol ^, so you have:

int *x; // a manually managed pointer to an int
int ^x; // a garbage collected pointer to an int

And it gets lots of nice typesafety like not being able to accidentally assign manually managed memory to garbage collected types, or vice versa.

It's really rather good. But not as good as C# :-)

Quote:

I could go on and on... It would be better just to write a new language that takes the best aspects of C++ and Java. D doesn't qualify.

C# 3.0 is my new favorite language.

C# 1.0 was ok, but a little bit too close to Java for my taste. It did add a few nice C++ things that Java is missing, like operator overloading, stack allocated structures, and the ability to do unsafe pointer arithmetic where you really need to optimize the crap out of performance critical inner loops, but the vast majority of day to day C# code felt very much like Java.

C# 2.0 got a whole bunch better with the addition of generics. While not as powerful as C++ templates, they are still very cool and enabled some really nice System.Collections.Generic collection types, easily on a par with STL for power and niceness. It also added anonymous delegates, which are incredibly sexy but have a clunky syntax.

C# 3.0 fixes the anonymous delegate syntax to allow really nice lambda expressions, and adds a whole bunch more functional style goodness. For me it really does combine the best of C++, Java, and ML (yes, ML: it's about time some of those cool functional ideas made their way into a mainstream production language, and I'm very happy this is finally starting to happen).

Marcello

Is it free to develop in C# though? For me, I see Java and C# as fairly similar, C# having the advantage of being newer and learning from things like Java (though I don't really see operator overloading as a good thing). It's certainly not worth using over Java if you have to pay for the IDE/compiler and only runs on Windows. I realize with mono that's not the case, but I don't know the specifics.

Marcello

Shawn Hargreaves

The .NET Framework 2.0 SDK (http://msdn.microsoft.com/netframework/) is free (as in beer), and includes commandline compilers for C#, J#, VB.NET, and JScript.NET.

If you want an IDE, Visual C# Express (http://msdn.microsoft.com/vstudio/express/visualcsharp/) is also free as beer.

And of course Mono is free (as both speech and beer).

Steve++

Shawn, now that you're a console-programming god, please tell us what the current state of affairs is with regard to programming consoles in different languages (other than C and C++ with a sprinkling of lua) such as C# and Java. Are those languages available? Supported? Viable? Often used? Which consoles?

Thanks.
- Steve

PS. Good to see you back here.

Shawn Hargreaves

At the moment there is almost no use of managed / jitted languages on console. Everyone seems to shoot straight from low level binary compiled languages (mostly C++) to mega dynamic bytecode languages (Lua or Python), skipping the intermediate level of jitted languages like C# or Java.

I think this is mostly down to lack of suitable execution environments. The console makers tend to spend a fairly minimal amount of time just getting gcc to work, which gives you the low level C++ support. Then when game teams realise they need something higher level and more dynamic, it is easy for them to port Lua or Python because those are implemented in such a clean way that the C bytecode interpreter can run on pretty much any machine without changes. It tends to be a case of each individual team throwing together their own port of the bytecode interpreter, and they don't have the resources to port anything complicated like a JVM or .NET runtime.

Which strikes me as a great pity, because these sort of jitted managed environments really do seem to be the sweet spot for enabling rapid software development (lots of nice high level features like reflection, late bound method invocation, and garbage collection) while still running at a decent clip (a good jitter can be surprisingly competitive against native code, and an order of magnitude faster than any of the bytecode languages).

Zaphos

Shouldn't that be a bit improved by XNA, though, at least for the 360? (I suppose this does one very little good for cross-platform development, though ...)

Shawn Hargreaves

No comment :-)

Zaphos

Hah. Well, Wikipedia says yes:

Wikipedia said:

The XNA Framework is based on the .NET Framework 2.0. It has been designed with an extensive set of class libraries, specific to game development exercises, to promote maximal code reuse across target platforms. It will also include a version of the Common Language Runtime, which is optimized for gaming requirements, to provide a managed execution environment to the XNA games. The runtime will be available for both Windows XP, Windows Vista and the Xbox 360. Since XNA games will be written for the runtime, XNA games will run on any platform supporting the XNA framework, with minimal or no modification. Games targeting the XNA framework can be written to using the C# language.

On a similar note, re programming languages and game development, Tim Sweeney has some interesting thoughts.

Shawn Hargreaves

Oh yeah, I forgot we did that press release. Cool!

I'm still not allowed to talk about it, though, because this is exactly what I'm working on at the moment and there's still a lot of stuff the marketing people are busy figuring out when and how to announce. You know how it goes, they don't want developers going and randomly spouting things in an uncontrolled fashion...

Richard Phipps

Quote:

You know how it goes, they don't want developers going and randomly spouting things in an uncontrolled fashion...

But that takes all the fun out of it! How else will random rumours spread across the net? :)

Shawn Hargreaves

Good point. In that case I certainly won't tell you that XNA is going to prove the power of our platform by demonstrating a Visual Basic port of Halo 3 running on a mobile phone.

Zaphos
Quote:

I'm still not allowed to talk about it, though,

Ah ... I did think it was odd that you were seeming to ignore your own project, which will, I think, have a rather significant impact on the question asked! ... but of course, loose lips sink ships and software development houses.

Quote:

I certainly won't tell you that XNA is going to prove the power of our platform by demonstrating a Visual Basic port of Halo 3 running on a mobile phone.

Hey, I hear the DOOM RPG is actually pretty good :)

Richard Phipps

I've seen the DOOM RPG on a phone. It's rather interesting. :)

Shawn: Now you'll be telling us that your companies next game doesn't feature motorbikes! :o

Shawn Hargreaves

Motorbikes?

Game?

I don't do games any more!

It's strange how close XNA feels to being back working on Allegro, actually. Instead of worrying about gameplay, I'm back to concerns like "will people actually understand how to use this API?", "is this flexible enough for all the crazy stuff they are going to want to do?", "how are we going to maintain this API as we extend things in the future?" and suchlike fun topics.

Richard Phipps

I suppose I can see the appeal of making a library rather than a game. :)
As long as you are having fun I suppose!

Marcello

It's certainly a more...reliable form of work.

Marcello

Shawn Hargreaves

That's actually very much how I approached game development in any case: I spent way more time building tools and reusable components than working on the actual game code! I always figured if we got the tools right, it would then be trivial and quick to slap a game together at the end, plus we'd be able to reuse the tools once we'd built them.

The nice thing about XNA though is I get to build tools for a much wider audience than just a couple of teams inside one company.

I find it fun, anyway!

Richard Phipps

I suppose that means more pressure in a way if it's for a lot of external teams. :)
Do you find you have developed as a designer now you are doing XNA work compared to Allegro?

Shawn Hargreaves
Quote:

I suppose that means more pressure in a way if it's for a lot of external teams.

In some ways, yes: things need to be much more robust and flexible and have good error handling and so on, where internally people could just come ask me if they couldn't figure it out.

In other ways this is easier, though, because I'm not so directly responsible for delivering an actual product. So there's a lot more room to say "sorry, that's just not something we support", where on a game team you don't have any wiggle room to not bother supporting exactly what the game needs!

Quote:

Do you find you have developed as a designer now you are doing XNA work compared to Allegro?

Hugely. I learned an incredible amount during my years at Climax, about how to make games, about teamwork, and about general software design.

Plus there have been so many advances in languages and naming conventions and design patterns and abstraction techniques over the intervening years, it's so much easier to make a nice usable API these days!

I'm finding a lot of the stuff I'm doing for XNA is much simpler than the code I wrote at Climax. Or at least has a simpler surface area. At Climax I got very into using advanced functional templatey C++ tricks in my tool code, which was very powerful and not always easy to understand :-) But fine as long as I was the only one who had to use the resulting API! For XNA we're targetting a completely different kind of developer, so I'm having to do a lot more thinking around what at first glance seem to be more superficial kind of usability issues like exactly what a method should be called, or giving related methods alphabetically related names so they sort next to each other in the class viewer. Little stuff that if we get it all right, makes the final product so much nicer to work with.

Richard Phipps

Sounds good! I didn't realise you weren't working at Climax anymore. I take it you work for Microsoft now?

I must admit I'm still a little confused about exactly what XNA is. :)

Shawn Hargreaves
Quote:

Sounds good! I didn't realise you weren't working at Climax anymore. I take it you work for Microsoft now?

'fraid so. I'm an American living in Seattle these days...

Quote:

I must admit I'm still a little confused about exactly what XNA is.

Many things. It's an umbrella marketing term for all the work MS are doing to make developer tools for games.

That include stuff around build systems for game content ("XNA Build"), and Visual Studio customization for managing game assets ("XNA Studio"), and depending on who you talk to, might also include DirectX and the Xbox SDK. It also includes making managed code work for writing games (the "XNA Framework"), which is the part I'm working on.

Marcello

Will it be free to use? :D

Shawn Hargreaves

Afraid that's one of the things they haven't announced yet...

axilmar
Quote:

For example, gl4java is a native library, and hardly recommended for production stuff.

Both the THALES RCMD console and VISU radar system are made with it, and they are quite fast. They could have been better if C++ was used, but the program manager insisted on Java, 4 years ago. But they had to double the specs to make it work.

Disclaimer : I worked in those projects.

Quote:

In Java 1.5 you do not need to create new Integer objects, as it's all transparent in the language. It does not create a new Integer object for each cast, but instead uses Integer.valueOf which has a bit more intelligent mapping.

Any object allocation is Java is not going to be as efficient as stack-based allocation. I challenge you to prove me wrong.

Furthermore, in Java 1.5 when you put an int in a list, an Integer object will be created automatically. It is the same as before, and generics is nothing more than syntactic sugar.

Marcello said:

The standard Java libraries are far better/easier to use than STL and boost.

You are comparing apples with oranges. The Java SDK contains a lot of things...STL is about algorithms and collections.

Compare java.utils with STL...STL is much better, both in performance and in usage.

Or compare Java SDK with Qt.

Quote:

Templates in C++ are evil.

Opinions are like asses nowadays: everybody has one. At least when I right down mine I try to justify it.

Quote:

C++ has to be compiled separately for each platform (windows/mac/linux/etc.).

Hardly a problem. Usually a product is compiled for Windows, Linux and Mac. With the proper libraries, no source code special to each O/S has to be written. Qt is the example here.

Quote:

Dynamic/reflective coding is near-impossible in C++.

Hardly ever needed.

Quote:

C++ cannot be run in a sandbox/secure "jail".

And why should it need to? security is not a function of jailing, but of design.

Quote:

DLL hell.

And you blame C++ for that??? if I made my dlls with Haskell, you would blame haskell as well?

Quote:

bloody. fucking. segmentation faults.

...which you would't have most of them if C++ had garbage collection.

Quote:

There's a lot of repeated code to write classes in C++ (.hpp/.cpp)

That's the only thing I agree with you. But a decent IDE can take care of that.

Quote:

Griping aside ;), doesn't managed C++ with .NET or whatever have garbage collection?

If you haven't heard, there are other O/Ses around, other than Windows.

Steve++ said:

I could go on and on... It would be better just to write a new language that takes the best aspects of C++ and Java. D doesn't qualify. I've looked at it a number of times and each time realised why I don't use it. It's got too much ugly syntax. The language itself is a bit bloated.

The cost of writing and verifying a new compiler (not for a toy language) is in the range of billion $$$.

Quote:

There's no perfect languages.

Nothing is perfect, but C++ with GC comes damn near closer.

Shawn Hargreaves said:

C# 3.0 fixes the anonymous delegate syntax to allow really nice lambda expressions, and adds a whole bunch more functional style goodness. For me it really does combine the best of C++, Java, and ML (yes, ML: it's about time some of those cool functional ideas made their way into a mainstream production language, and I'm very happy this is finally starting to happen).

Indeed, functional programming languages have some very good features: combinators, lambda functions etc.

But I won't touch C# as long as it is not open source...not free as in beer, but free as in speech, and available for other O/Ses as well...and not only the compiler, but the libraries as well (because the compiler alone is worthless).

Archon
Quote:

But I won't touch C# as long as it is not open source...not free as in beer, but free as in speech, and available for other O/Ses as well...and not only the compiler, but the libraries as well (because the compiler alone is worthless).

.GNU and Mono are free and cross-platform. They're not exactly the cross-compatible and feature-filled equivilent of .NET 3.0 since they don't exactly have the resources, but they'll get there sometime.

nonnus29
Quote:

Is it free to develop in C# though? For me, I see Java and C# as fairly similar, C# having the advantage of being newer and learning from things like Java (though I don't really see operator overloading as a good thing).

The bad thing about sun's control of java is (in particular) the java generics fiasco: Sun would not change the vm AT ALL to provide features to support generics. By association, it's just as unquestionable for sun to change the vm to allow ways to simplify the implementation of ML style constructs (it's possible to do ML in java bytecode; google for 'mlj' - I think they ported this to .net as well).

MS apparently has no such problem making changes to the clr.

Shawn Hargreaves
Quote:

Any object allocation is Java is not going to be as efficient as stack-based allocation. I challenge you to prove me wrong.

I don't know about Java, but in the desktop version of the .NET CLR the implementation of allocating a new object on the heap is literally as simple as:

void *addr = gHeapPtr;
gHeapPtr += sizeof(typeBeingAllocated);
if (gHeapPtr > gHeapEnd)
    CollectGarbage();
return addr;

In the case where no GC is triggered, this is exactly the same cycle count as a stack allocation! (assuming that your compiler switches are set to check for stack overflows, which almost all modern apps are built with for security reasons).

Of course it's not as fast as stack allocation when a GC is triggered, but even then it is pretty fast. This is one of those things that in theory sounds like it could be slow, but in practice I've never seen GC overhead even show up on a profiler for well written code. In fact I find myself spending way less time optimising C# to avoid GC overhead than I did in C++ to avoid malloc() overhead. It pretty much "just works" and runs fast. Heap allocating short lived objects (things that don't last long enough to get promoted out of generation 0) is really very similar to the performance of stack allocation in C++. But with stronger correctness guarantees.

Quote:

Furthermore, in Java 1.5 when you put an int in a list, an Integer object will be created automatically. It is the same as before, and generics is nothing more than syntactic sugar.

Yeah, Java sucks :-) C# on the other hand has true generics built into the runtime, not just as compiler trickery, so a strongly typed list of ints does not require any boxing. Which is as it should be.

Quote:

Quote:

Dynamic/reflective coding is near-impossible in C++.

Hardly ever needed.

Really? I find myself using reflection all the time. It is an immensely powerful way to step outside the statically typed universe and do cool Pythonic tricks: gives you a big chunk of the goodness of dynamically typed languages while still keeping static typing for all the places where that makes sense.

Reflection is particularly invaluable for writing unit tests. We have very high automated test coverage for all the code in my current project (probably more test code than actual production code), and this would be almost impossible to achieve without reflection. How else could you poke around in the guts of a running system to check everything is working as expected, or to simulate obscure internal error cases?

Quote:

.GNU and Mono are free and cross-platform. They're not exactly the cross-compatible and feature-filled equivilent of .NET 3.0 since they don't exactly have the resources, but they'll get there sometime.

I'm actually really impressed with Mono - it works great and is surprisingly close to the MS feature set. I don't know when they'll get the .NET 3.0 features online, but after .NET 2.0 was announced, they actually had generics working in Mono way before MS got around to releasing a beta of their implementation!

Zaphos
Quote:

But a decent IDE can take care of that.

That's another issue with C/C++ -- seems that because of all the preprocessor support, it's a lot harder to find an IDE which refactors & which compiles (and underlines errors / warnings) as you type/save. Does such exist?
I find I edit Java in Eclipse, and C++ in SciTE, so writing Java code is a lot nicer.

Quote:

And why should it need to? security is not a function of jailing, but of design.

Isn't jailing a design? It seems like the only way to provide gaurantees about the code, short of having it carry proofs ... I'm not sure why you would dismiss this as worthless out-of-hand.

The 'niceness' of Java also seems to mean it gets neat things like the omniscient debugger first and more freely ...

edit:

Quote:

...which you would't have most of them if C++ had garbage collection.

You'd could still access arrays out of bounds, deference null pointers, overwrite memory, etc ... and segfaults are really quite a liability, security-wise ... It still seems like a real advantage to get rid of them completely.

HoHo

How would you eliminate pointer calculations? Would you cut out inline assembly also because that would allow modifying pointers and data on lower level than the language might.

Zaphos
Quote:

How would you eliminate pointer calculations?

Was that question aimed at me? I wasn't talking about changing C++, I was talking about using Java ... merely claiming that the lack of segfaults in Java is still a benefit to some extent.

Shawn Hargreaves
Quote:

How would you eliminate pointer calculations

There are various schools of thought on pointers.

1: The C++ approach. If you do it right it will work. If not, it won't. It's your problem.

2: The Java approach. Pointers are unsafe, therefore don't allow them.

3: The academic approach. Figure out some kind of code analysis algorithm that can verify whether pointers are being used correctly. Nice idea but unfortunately nobody has figured out how to actually do it yet :-)

4: The C# approach. Pointers are unsafe, therefore you shouldn't use them very much. It should be possible to write the vast majority of day to day code using constructs that are guaranteed typesafe and cannot corrupt memory. But sometimes you just need to do something low level and icky, or you are writing performance critical code, so you should still be able to use pointers when you really need them. Code that uses pointers will have less safety guarantees than code which does not, so it needs to be clearly labelled, making sure you can spend extra time reviewing these few risky areas. The language should encourage gathering up the unsafe pointer usage into just a few reusable functions, rather than scattering it all over the main body of the code.

How this works in practice:

1// Array indexing using integers (does overflow checks every time you index into the array)
2for (int i=0; i<array.Length; i++)
3 Console.WriteLine(array<i>);
4 
5// Array indexing using enumerators (usually faster because the enumerator can be optimized to avoid repeated overflow checks)
6foreach (string value in array)
7 Console.WriteLine(value);
8 
9// If I want to be unsafe I can. But I usually don't want to or need to.
10unsafe {
11 fixed (string* ptr = array) {
12 string* end = ptr + array.Length;
13 
14 while (ptr != end)
15 Console.WriteLine(*(ptr++));
16 }
17}

Zaphos
Quote:

The academic approach. Figure out some kind of code analysis algorithm that can verify whether pointers are being used correctly. Nice idea but unfortunately nobody has figured out how to actually do it yet :-)

I categorized the academic approach as more like Cyclone or Typed Assembly Language ... which do, as far as I can tell, have working implementations. I don't think anyone's expecting an after-the-fact code analysis to be able to verify such things generally -- that seems like it's obviously not possible (since you could construct, you know, a program that only uses pointers incorrectly if it finds a counterexample to [insert famous theorem here]). Code analysis techniques like Model Checking are more additional debugging aids than full solutions ...

Richard Phipps

With CPU speeds now faster than ever, aren't we approaching the point where low-level pointer operations should be replaced with slower (but safer) methods of manipulating data?

HoHo
Quote:

Was that question aimed at me?

Yes but I think I misunderstood you. When you said "It still seems like a real advantage to get rid of them completely." I thought you were talking about getting rid of any possibility to cause segfaults by eliminating all things that can cause user-errors (pointers, overflowing arrays and other stuff)

Quote:

With CPU speeds now faster than ever, aren't we approaching the point where low-level pointer operations should be replaced with slower (but safer) methods of manipulating data?

In about 95% of the cases, yes. For them CPU speed is fast enough. Problem is that the other 5% still needs at least some tuning and part of that needs extreme tuning. Difference between non-optimized code and optimized code can be several orders of magnitude, even when the general algorithm is the same.

Shawn Hargreaves
Quote:

With CPU speeds now faster than ever, aren't we approaching the point where low-level pointer operations should be replaced with slower (but safer) methods of manipulating data?

For 99% of code, yes.

But there is still that final 1% to worry about.

For instance I just got done writing a class for doing design time texture manipulation (creating mipmaps and so on). To the people using this, it looks like a 2D array, and the methods for reading and writing pixels do bounds checking. But internally I need every bit of speed I can get. If it takes me a couple of extra hours dealing with more complicated coding constructs, but in exchange I can speed up some common image processing operations by 20% for everyone using the library, that seems like a worthwhile tradeoff.

Personally I like to have the choice. Use slower and safer methods by default, but have an emergency switch that I can throw in case I really need to.

This is kind of the same thing as people who write big apps in Python, but then optimize a few critical sections in C. Except just sticking an unsafe tag in the middle of some C# code is much easier than dealing with all the Python to C interop hassles.

The ability to drop down to raw pointer artihmetic is also very useful when doing interop to existing non-managed code. Of course in an ideal world everything would be managed and typesafe and good, but we don't live in an ideal world. Sometimes you're writing high level managed code and badly need to call some icky low level system API that was designed 15 years ago and is inherently untypesafe. I find it very handy that I can just wrap the thing in an unsafe tag and have at it: no need to jump through hoops using some other language to make a wrapper.

Goalie Ca
Quote:

But I won't touch C# as long as it is not open source...not free as in beer, but free as in speech, and available for other O/Ses as well...and not only the compiler, but the libraries as well (because the compiler alone is worthless).

C# is a pretty nice language and i've done work in it. THe main problem i've had with c# is the lack of good strong libraries. Windows Forms is terribly incomplete (though consisten) and it uses GDI+ instead of GDI which means no hardware acceleration for things like blitting images (which means its makes a terribly slow picture viewer unless you bother to p/invoke gdi and winapi).

Mono is pretty nice and i use several mono applications including beagle and tomboy. A lot of beagle core is actually still in c++ for various reasons. Mono apps seem to run just as fast as the rest (because they all use c libraries in the end).

gtk# and glade# are pretty nice and there's gecko# gimp# and everything else in the gnome world. qt# was sadly canned after the people lost interest. QT is an awesome toolkit.

Last summer i wrote some numerical code in c# for some basic image processing. I took some time, read a lot of docs, followed good practices, turned off all the safety stuff, and it still ran 2-4 times slower than naive c++ (compiled with mingw). Obviously though c# is not designed for that stuff. Actually if you think about it matlab is horrendously slower (but syntactic gold).

I love c# for writting everyday applications but for me c++ is awesome for everything else. I do a lot of image processing, numerical analysis (often i call fortran code which can optomize a lot better because of constraints like lack of pointers etc.)

Quote:

You'd could still access arrays out of bounds, deference null pointers, overwrite memory, etc ... and segfaults are really quite a liability, security-wise ... It still seems like a real advantage to get rid of them completely.

Which is why you try and use nice helper objects which throw exceptions where speed doesn't matter. They are speaking of making the next version of the STL entirely "safe" and having an unsafe one available for those who count cycles. But ya, pointer abuse is one of those things that make C++ a real drag. Smart pointers go a long way to fixing that but are not perfect themselves.

I was also pleasently surprised last summer when i discovered that i could write void* in c# and have it compile. I believe though that i needed to mark the function using the "unsafe" keyword. That seems like a perfectly reasonable thing to do. It's basically the equivalent of casting to/from type object.

Quote:

With CPU speeds now faster than ever, aren't we approaching the point where low-level pointer operations should be replaced with slower (but safer) methods of manipulating data?

Hell no! Although i must admit that my "research code" for my biomedical engineering thesis uses a lot of checking and such so it takes overnight to run instead. There are a few performance critical areas where i could fix it but since i'm constantly modifying the code it would be suicide. That aside it would be marvelous if once it stabilizes i could run it in even 70% of the time. Don't forget that there are a LOT of cases where even an algorithm of nlog(n) is far too large and every cycle counts (especially every branch! especially with blocking and multi-threads/processes)

edit: In particular i'm using smart pointers, very "safe" collections, built checking in them, etc. The best thing any compiler could do in my opninion is throw compile time errors and warnings. The more the better. I always make my code work to output no warnings even and gcc 4 makes things a lot "stricter".

Steve++

I love Java, but the more Shawn extols the virtues of C#, the more I lean towards it. Ah heck, I'll write my next game in C# just for fun.

topicms.gif

axilmar
Zaphos said:

That's another issue with C/C++ -- seems that because of all the preprocessor support, it's a lot harder to find an IDE which refactors & which compiles (and underlines errors / warnings) as you type/save. Does such exist?
I find I edit Java in Eclipse, and C++ in SciTE, so writing Java code is a lot nicer.

Eclipse can edit C++, but I haven't tried the refactoring capabilities yet. But it is certainly doable in C++ as it is in Java, because the preprocessor is not used heavily in C++ to provide code; that's unlike C, where certain tricks are only possible through the preprocessor.

Quote:

Isn't jailing a design? It seems like the only way to provide gaurantees about the code, short of having it carry proofs ... I'm not sure why you would dismiss this as worthless out-of-hand.

It is a totalitarian design. It puts unneeded constraints. It is certainly not worthless, but security could be done without it.

Quote:

The 'niceness' of Java also seems to mean it gets neat things like the omniscient debugger [lambdacs.com] first and more freely ...

www.parasoft.com

Quote:

You'd could still access arrays out of bounds

vector.at is your friend.

Quote:

deference null pointers

ptr<T> is your friend.

Quote:

overwrite memory

Not really possible with GC and guarded pointers.

Quote:

etc ... and segfaults are really quite a liability, security-wise ... It still seems like a real advantage to get rid of them completely.

Not really. The vast amount of problems in C++ come from manual memory management. If you do not believe me, check out com.std.c++.

HoHo said:

How would you eliminate pointer calculations? Would you cut out inline assembly also because that would allow modifying pointers and data on lower level than the language might.

You don't have to eliminate pointer calculations. In C++, you don't pay for what you don't use. Let them do pointer calculations if they want to screw their program...if you don't, provide a special pointer class which can easily do guarded pointer arithmetic. That's a task that can hapilly exist in a library, unlike gc.

Richard Phipps said:

With CPU speeds now faster than ever, aren't we approaching the point where low-level pointer operations should be replaced with slower (but safer) methods of manipulating data?

There are everyday tasks that require speed. Try Sql Server Express, a .net managed app...slow as hell. Then try VS...not as slow, but slow nevertheless. Also try to edit a 265-page word document with technical schematics...each time you add something, word will repaginate the document, taking lots of time to do that. And what about compiling?

Let's not kid ourselves. The day performance does not matter is not here yet.

Shawn Hargreaves
Quote:

And what about compiling?

Interestingly, the Microsoft C++ compiler is written in C++, while the C# compiler is written in C#.

Guess which runs fastest?

(ok, so that's not really a fair test because they aren't both compiling the same language. But I still find it interesting)

The Visual Basic compiler, however, is not written in Visual Basic. Conclude from that what you will :-)

Marcello

That odb thing looks pretty neat. D: But hasn't been updated in over a year? It'd be nice if it integrated into Eclipse...

Marcello

Zaphos
Quote:

But it is certainly doable in C++ as it is in Java, because the preprocessor is not used heavily in C++ to provide code; that's unlike C, where certain tricks are only possible through the preprocessor.

The preprocessor is just as powerful & available, though, so if it can't work in C then it can't work generally in C++.

Quote:

It is a totalitarian design. It puts unneeded constraints.

Er ... how else can you make guarantees about the safety of a binary?

Quote:

www.parasoft.com

Um, I'm not familiar with their entire product catalog, but they don't seem to offer a backwards debugger. And if they do, it seems unlikely it will be free.

Quote:

Let them do pointer calculations if they want to screw their program...if you don't, provide a special pointer class which can easily do guarded pointer arithmetic.

The C# approach described by Shawn seems far preferable.

Arthur Kalliokoski
Quote:

Interestingly, the Microsoft C++ compiler is written in C++, while the C# compiler is written in C#.

Guess which runs fastest?

I'll take Greek Mythology for $500, Alex!

I'll byte and say that C++ is faster... OTOH he wouldn't have stated the quote otherwise since it wouldn't have been "newsworthy"

Shawn Hargreaves

Curiously, the C# compiler is literally about 100x faster than the C++ one!

And that's even without it bothering to implement any of the clever speedup techniques the C++ compiler uses, like precompiled headers, incremental linking, and so on.

The speed difference is just ridiculous. In C++ you get totally used to large projects taking several minutes if not hours to compile. But in C#, a codebase similar in size to Allegro compiles in about 5 seconds. It's just crazy.

That's mostly down to the language, though, which is designed to avoid constructs that will give the compiler anything too time consuming to worry about.

Curious factoid: Anders Helsborg, the chief designer of C#, previously invented Delphi and before that Turbo Pascal. Both also languages notorious for having ridiculously fast compile times.

Goalie Ca

THe MS VC++ compiler sucks donkey balls. It chokes on templates and simple stuff all the time. But that has absolutely nothing to do with "which language is the best".

Zaphos

I hear the MS VC++ compiler is quite good -- and it certainly seems to be respected and used in industry. Perhaps you're thinking of an older version?
And since Shawn's claims seems to extend generally across all C++ compilers -- I've never seen a C++ compiler that can get the compile-speed that Shawn's seeing for C# -- it does apply as a language critique. A faster compile-time means less time lost waiting for builds, which means more productivity.

edit: this actually means a lot to me -- a build time of a few seconds keeps me focused on the task at hand. If I have to wait a few minutes to get back to my project and test out my changes, I'll probably use those minutes to start checking my email or the boards or etc, and often waste a lot more than the actual time-to-build. And when I get back to the problem, it's less fresh in my head, so there's more lost productivity getting re-oriented.

Steve++
Quote:

Curiously, the C# compiler is literally about 100x faster than the C++ one!

Even if the C# compiler was written in a native language such as C++, I doubt it would be any (or much) faster, because compilers spend a lot of time in disc access.

Quote:

Curious factoid: Anders Helsborg, the chief designer of C#, previously invented Delphi and before that Turbo Pascal. Both also languages notorious for having ridiculously fast compile times.

I remember using Turbo C and Turbo Pascal on the same machine (just running DOS). Pascal compiled way faster than plain old C. This guy should also be working on the C++ compiler team.

Quote:

THe MS VC++ compiler sucks donkey balls. It chokes on templates and simple stuff all the time. But that has absolutely nothing to do with "which language is the best".

Templates take a lot of time to process. If C++ had a proper generic system then it wouldn't need templates to thrash the compiler and bloat the binary.

Quote:

I hear the MS VC++ compiler is quite good -- and it certainly seems to be respected and used in industry. Perhaps you're thinking of an older version?

Even verson 6 was used widely in the industry, so I guess it was 'respected' too, but that was full of ISO/ANSI non-conformance.

Zaphos
Quote:

This guy should also be working on the C++ compiler team.

Maaaaybe, but it seems like designing a language so that it is easy to compile is quite different from optimizing a compiler for a language which already has its spec finalized ... there's no particular reason to believe this guy could significantly speed up the C++ compiler.

Quote:

but that was full of ISO/ANSI non-conformance.

I think this was primarily because it was created before the standards solidified, so it's not really fair to fault them for it.

_Dante

Good God, this thread still hasn't been shut down? You are all aware that the question was asked and answered in the first two posts, and everything since then has been off-topic, right?

Thomas Fjellstrom

Welcome to Allegro.cc _Dante. :)

So long as it isn't a flaming ball of trolls these sorts of discussions can be informative to some.

LennyLen
Quote:

You are all aware that the question was asked and answered in the first two posts, and everything since then has been off-topic, right?

Welcome to allegro.cc. ;)

[edit]D'oh!

_Dante
Quote:

Welcome to allegro.cc. ;)

Point taken. Uh, I'll cast my vote for APL (am I dating myself there? Nah.)

Kitty Cat
Quote:

I think this was primarily because it was created before the standards solidified, so it's not really fair to fault them for it.

When will it support C99? :P Why is it replacing/deprecating the majority of libc in the name of "safety" and "security", when several of the functions could only be a safety concern if an absolute idiot got a hold of them? Most of the rest are also fine as long as you use it properly.

HoHo
Quote:

I hear the MS VC++ compiler is quite good -- and it certainly seems to be respected and used in industry.

I wonder why is that so.
ICC beats almost everything under the sun for 32bit x86, gcc gomes next. In 64bits GCC 4.1+ is the greatest followed by ICC. Well, at least for compiling code with lots of SSE2 intrinsics. For 32bit Allegro on Linux GCC 3.4 is faster than ICC :)

[edit]
I was talking about generated code speed, not compiling time.

Zaphos
Quote:

ICC beats almost everything under the sun for 32bit x86, gcc gomes next.

Source? Is that true for AMD chips as well?

Steve++
Quote:

ICC beats almost everything under the sun for 32bit x86, gcc gomes next.

My understanding is that MSVC++ generates smaller and fastser code than gcc because it doesn't have a front-end/back-end architecture; or if it does to some degree, the 'intermediate' form isn't as far removed from the target hardware as is the case with gcc (because gcc targets a wide range of architectures).

Marcello

The reason the C# compiler is so much faster than the C++ compiler is similar to the reason the Java compiler is so much faster than the C++ compiler. You're not building/linking the entire program, you're making dynamically linked modules. Plus on top of that, the languages are a bit more strict and don't have to worry about things like preprocessors (eg #include).

Marcello

Steve++

I can only speak for Java...

Java has an integrated build system. You compile one file and if another is needed, that is compiled first, and so on. But if the dependency (which is always just a class) is already compiled, then its interface is very easily and quickly extracted from its class file. I think C++ should modernise its compilation system similarly and rid itself of its preprocessor legacy once and for all. Also, another annoying legacy that should die in C++ is that a global or class identifier must be declared above the code that first references it.

C++ was designed to be a better C. It's time for a better C++.

HoHo
Quote:

Source?

http://ompf.org/forum/viewtopic.php?p=1153#1153
Download that file. Compile with maximum optimizations and see the difference. IIRC under win32 ICC was fastest, next came GCC 4.2 alpha being ~10% behind and last was MSVC 2k5 ~5% slower than GCC.
Under 64bit GCC was fastest, ICC ~5% slower and MSVC ~10% slower than GCC.
I haven't personally done those tests but others in that forum had and I think I can trust them.

As for code size, I don't know. Most likely ICC generated the biggest and MSVC the smallest

Quote:

Is that true for AMD chips as well?

ICC bypass or how to keep dirty monopolist at bay. :)
[edit]
Got rid of recursion :)

Marcello
Quote:

and MSVC ~10% slower than MSVC

ahhh the recursion! make it stop!

Marcello

Zaphos
Quote:

Download that file. Compile with maximum optimizations and see the difference. IIRC under win32 ICC was fastest, next came GCC 4.2 alpha being ~10% behind and last was MSVC 2k3 ~5% slower than GCC.

So, for some random raytracer, a two-year-old version of MSVC is slower than an unknown version of ICC and the GCC 4.2 alpha? Um, this benchmark seems ... broken ...

HoHo
Quote:

ahhh the recursion! make it stop!

Got rid of it :)

Quote:

So, for some random raytracer, a two-year-old version of MSVC is slower than an unknown version of ICC and the GCC 4.2 alpha?

Oops, they used 2005 instead. The last version I used was 2k3, thus the confusion.
ICC version was the latest, 9.1.
Newer GCC has vastly improved SIMD code generator, thus the alpha. I'm not sure if GCC 4.1 series have the same optimizations or not.

Quote:

Um, this benchmark seems ... broken ...

If you don't remember what I said before in ]edit I'll say this again:
... at least for compiling code with lots of SSE2 intrinsics
So when dealing with that topic narrowing my "benchmark" is correct :)
Btw, that ray tracer should currently be one of the fastest single-threaded ray tracers in the world if not the fastest. Too bad it currently only supports primary rays and no textures. Those problems should be fixed soon and also it should have extremly good support for completely dynamic scenes. Tracing those dynamic scenes is almost as fast and efficient as tracing static scenes.

When comparing some random code ICC should mostly be a bit faster than GCC and MSVC is usually the slowest. Of course there might be exceptions but that is what I and some other people I know have seen.

Zaphos
Quote:

So when dealing with that topic narrowing my "benchmark" is correct

Ah! Probably. As correct as benchmarks tend to get, anyway :)

Quote:

When comparing some random code ICC should mostly be a bit faster than GCC and MSVC is usually the slowest. Of course there might be exceptions but that is what I and some other people I know have seen.

All right. I'll file it under "probably usually true," then ;). Thanks for all the clarifications -- casually googling, it's hard to find good (up to date) data on this!

Quote:

Btw, that ray tracer should currently be one of the fastest single-threaded ray tracers in the world if not the fastest.

Cooool! I hope it gets features soon!

Marcello

I made a ray tracer that's even faster! It can render everything in under a second. Although it's limited to 1x1 renders. It does support antialiasing though.

Marcello

Zaphos
Quote:

It does support antialiasing though.

;D

axilmar
Zaphos said:

The preprocessor is just as powerful & available, though, so if it can't work in C then it can't work generally in C++.

No, you don't understand. In C, certain things are only/much easier doable through the preprocessor. Take linked lists, for example: a couple of macros will save you from casts. You don't need to do stuff like that in C++.

Quote:

Er ... how else can you make guarantees about the safety of a binary?

The key is the word 'unneeded'. You can ensure a binary module does nothing serious if the O/S does not let it do anything serious. It is the O/S that hands privileges out. Unfortunately, O/Ses do not provide the proper 'sandboxing' of applications, so VMs take over. A proper sandboxing of an exe would be ring protection, like in CPU: an exe could not touch resources of a higher privilege level; unfortunately no O/S implements this.

Quote:

Um, I'm not familiar with their entire product catalog, but they don't seem to offer a backwards debugger. And if they do, it seems unlikely it will be free.

Yes, it's not free, but the point is it is doable.

Quote:

The C# approach described by Shawn seems far preferable.

If something can be in a library, then it need not be in the language.

Quote:

Templates take a lot of time to process. If C++ had a proper generic system then it wouldn't need templates to thrash the compiler and bloat the binary.

C++ templates are preferrable to generics. I do not want objects to be allocated each time I use primitives.

The compile speed difference is not as important as it sounds, because projects are developed incrementally anyway.

Evert
Quote:

In C, certain things are only/much easier doable through the preprocessor. Take linked lists, for example: a couple of macros will save you from casts.

Eh? Sorry, but what are you talking about?
I use linked lists all the time in C and I've never remotely needed a preprocessor. Then again, I've never needed to cast either.

Marcello
Quote:

The key is the word 'unneeded'. You can ensure a binary module does nothing serious if the O/S does not let it do anything serious. It is the O/S that hands privileges out. Unfortunately, O/Ses do not provide the proper 'sandboxing' of applications, so VMs take over. A proper sandboxing of an exe would be ring protection, like in CPU: an exe could not touch resources of a higher privilege level; unfortunately no O/S implements this.

So your point is moot, is it not? We don't live in utopia, we have to work with what we have. ;)

Marcello

Zaphos
Quote:

You don't need to do stuff like that in C++.

Yes, but you can, and the refactoring tech is supposed to work generally. Of course, you could have refactoring tech that just breaks down when macros are being abused ("error: code is stupid") but it seems less good then. Also, I think templates are essentially another turing complete macro system, under the hood, so it seems like you could trip up refactoring tech with that, too.
(Tangentially, I am familiar with using icky macros in C, and have done the linked list thing.)

Quote:

unfortunately no O/S implements this.

What Marcello said.

Quote:

but the point is it is doable.

Yeah, I never argued with doable. I just said easier and (hence) more free in Java.

Quote:

If something can be in a library, then it need not be in the language.

It can be more friendly when in the language. In C#'s case, it'll make it a lot nicer when you come in to a code base which you didn't have full control over, because the design of C# should make it really easy to see the unsafe code and it should also discourage its use.

Quote:

I do not want objects to be allocated each time I use primitives.

That's not really how the C# generics work, so all you seem to be saying is that you don't want Java Generics in C++.

C++ templates are also a pain, language wise, 'cause the compiler errors they give are often difficult to read.

Quote:

The compile speed difference is not as important as it sounds, because projects are developed incrementally anyway.

To some extent, one would hope, anyway.

Marcello

Compile time isn't incremental as soon as you're including other .hpp files. As soon as you modify a class, everything that uses it has to be recompiled, potentially everything.

In Eclipse, there is no compile time, everything is compiled automatically. :D

Marcello

GullRaDriel

If something can be in a library, then it need not be in the language:

Are you so sure to proudly tell that ? Tell me if I am wrong, but aren't all the language a couple of header and libraries ? Haaa, yes, you have the compiler. But with only one of these you can't do something. I really do not agree here.

For the C memory question: You can do as error as you can make in C++ for example. Forget to write a destructor or a free(...), and the result will be the same. Everything is a matter of debugging. Garbage collector ? Heh, do not assume everything is nicely done there. I think we can easily find that most of the time, That is the OS who take care of freeing memory for you. There are really mad code everywhere. And even if the memory is perfectly managed, you can not be sure that the RAM or DDR will keep it's efficiency for eternity ;-)

The speed question is a false question. Most of the application you will have to program for a company will not need the so/most/ever coded/optimized code. Companies are like that: As it is and works, as it should stay. Only the FBI,NASA,CNRS and allegro.cc's people must ;-)

For the project part: I got a C++ project who was rewritten 3 times and who is more than 10 years old. It has gone trough lisp, C, C++. Can you imagine how painless it is to have a variable or a function, and spend 10 minutes to understand from where it comes, and from where comes the derived overloaded polymorphic obscur class ?
Perhaps it is me, but read someone C++ giant project is as trying to understand his mind. I do not say it is not the case in C, but I find it more friendly when it comes to 'get' how a ten millions lines code works. IMHO !

And as I said before, Use the language you are the best at. And as Marcello said, you will not ever have the choice.

Greets, Gull.

_

Bob
Quote:

If something can be in a library, then it need not be in the language:

Are you so sure to proudly tell that ?

This is a requirement for all C++ specification changes. If some feature can be done as a library, it should not be in the language.

Goalie Ca
Quote:

Perhaps it is me, but read someone C++ giant project is as trying to understand his mind. I do not say it is not the case in C, but I find it more friendly when it comes to 'get' how a ten millions lines code works. IMHO !

What you are reffering to is overdesign and i see it all the time from keen comp sci students. It's sick how "generic" and "Abstract" people write the code.

I see it in C++ with even simple things like Array containers.

I've never though seen it in C. People keep things simple. I'm not sure why. Perhaps because its ugly to do things like this in the language or maybe its just the people and the purpose but generally people don't aim for "purity" and "perfection" they just aim to make it readable and short.

Zaphos
Quote:

I've never though seen it in C. People keep things simple.

It's worth noting, here, that it's possible to write unreadable code in any language. And people will do it. (hmm, ever tried reading any of James Lohr's source code?) In C, I think the more common problem is, er, under-design ... in which the code has been written as one amorphous mass, entirely lacking generality, so when it comes time to extend the code to new uses & such, it can get quite painful. And since your C IDE probably lacks sweet refactoring tools, it can be a lot harder to clean up than similar code would have been in, say, Java.

Quote:

This is a requirement for all C++ specification changes. If some feature can be done as a library, it should not be in the language.

But this doesn't justify it as a design philosophy . . . or imply that the features discussed could be done as well if they were in library form.

axilmar
Quote:

Yes, but you can, and the refactoring tech is supposed to work generally. Of course, you could have refactoring tech that just breaks down when macros are being abused ("error: quote is stupid") but it seems less good then.

Refactoring in C++ is doable just as in Java. Macros do not obcure anything, and almost never used in C++ declarations anyway.

Quote:

Also, I think templates are essentially another turing complete macro system, under the hood, so it seems like you could trip up refactoring tech with that, too.

Yeah, templates are a great idea.

Quote:

(Tangentially, I am familiar with using icky macros in C, and have done the linked list thing.)

as If I knew it...I've also done so, and I suspect many others have.

Quote:

Yeah, I never argued with doable. I just said easier and (hence) more free in Java.

Ok, it's a little bit easier for a JVM, but it's a minor point though. And it does not concern the language, because a C++ compiler could happily emit bytequote.

Quote:

It can be more friendly when in the language.

If it covers your needs and it is not in the language, then why isn't it as friendly as if being in the language?

Quote:

That's not really how the C# generics work, so all you seem to be saying is that you don't want Java Generics in C++.

Actually, they are. For example, when you add an int to a linked list, an Integer object is created. That's why the environment can keep one version of linked list around (as opposed to C++ where there are many versions of linked lists).

I don't like generics, because they make program less fast than it can be; it bloats memory with unnecessary objects etc.

Quote:

C++ templates are also a pain, language wise, 'cause the compiler errors they give are often difficult to read.

That's an implementation detail of the compiler. It does not concern the language. In MSVC++ 8.0, for example, template error messages are much more understandable.

Quote:

Compile time isn't incremental as soon as you're including other .hpp files. As soon as you modify a class, everything that uses it has to be recompiled, potentially everything.

In Eclipse, there is no compile time, everything is compiled automatically. :D

Marcello

Eclipse supports autocompile for C++ also. It works like in Java...try it.

Shawn Hargreaves
Quote:

Refactoring in C++ is doable just as in Java. Macros do not obcure anything, and almost never used in C++ declarations anyway.

Of course refactoring is technically doable in C++: you can always write a program to programmatically manipulate code written in any well defined language.

The point is not that it is impossible, but that it is much harder to get right.

So in the real world (the world of tools I can actually download and use today, rather than theoretical ones that haven't been written yet) it turns out that there are far more refactoring tools for Java and C# than there are for C++, and these have much richer features and are more robust.

Quote:

Quote:

It can be more friendly when in the language.

If it covers your needs and it is not in the language, then why isn't it as friendly as if being in the language?

It depends on the feature. Some things are fine in libraries, but others can benefit from dedicated language support for many possible reasons:

  • Better error reporting.

  • More efficient code generation.

  • Nicer syntax.

For example take a typical lock idiom implemented via a library in C++:

{
    LockHolder lock(theObject);
    object->doStuffWhileLocked();
} // LockHolder destructor releases the lock

Versus built into the language in C#:

lock (theObject)
{
    object->doStuffWhileLocked();
}

Not a huge difference, but the C# version is slightly more concise, and more importantly, less error prone because the braces are enforced as part of the construct, rather than just relying on scoping rules to release the lock at the right place.

Another example is lambda functions. boost::lambda does an amazing job of implementing them in a library, but has lots of corner cases that can be very confusing in practice. Nowhere near as clean and easy to understand as the C# delegate syntax.

Of course not everything belongs directly in a language, but some things can be made nicer that way.

Quote:

Quote:

That's not really how the C# generics work, so all you seem to be saying is that you don't want Java Generics in C++.

Actually, they are. For example, when you add an int to a linked list, an Integer object is created.

You are mistaken about how C# generics work, and are describing the Java implementation here. C# generics do not cause any unneccessary boxing.

Quote:

Quote:

C++ templates are also a pain, language wise, 'cause the compiler errors they give are often difficult to read.

That's an implementation detail of the compiler. It does not concern the language. In MSVC++ 8.0, for example, template error messages are much more understandable.

Better than they were before, but still far from ideal.

Like the point about refactoring, this is the difference between theory and practice.

Yes, poor error messages are an implementation detail.

But also, the C++ template system makes it hard to give good error messages, as witnessed by the fact that no C++ compiler which actually exists today can come anywhere near the clarity of the errors you get from misusing generics in C# or Java.

I actually kind of like templates because they are cool and powerful: I'm not one of those people who thinks they are the spawn of Satan. But I'm also aware that they have a lot of issues, high on the list being that a lot of people just don't understand them (which is not aided by generally poor error reporting). So if I'm writing a library that I intend to be used by a wide audience, heavy reliance on templates is probably not a great idea. Generics do much better in that regard. The typical idiot Visual Basic programmer who barely knows enough to string together a couple of forms for his business would be totally lost if you handed him a template API, but can generally get on ok with using generic container types.

23yrold3yrold

I had wondered why people were bashing templates. I just resurrected my old template particle engine for a project for the church and while the syntax is still ugly, I had cool fireworks and crap running in no time. I don't even remember how the stupid thing works under the hood, I just remember if you make this one class for initialization and this other class for logic and throw them at the template class and call Emit ... voila! Perfect fast particle management every time. :)

Zaphos
Quote:

Eclipse supports autocompile for C++ also. It works like in Java...try it.

That feature just calls "make" whenever you save, and isn't recommended. The Eclipse CDT manual, right in the "before you begin" section, states: "For C/C++ projects this feature should be turned off, otherwise builds will be performed whenever a file is saved, including makefiles and header files."

Thomas Fjellstrom
Quote:

I actually kind of like templates because they are cool and powerful: I'm not one of those people who thinks they are the spawn of Satan.

I love to hate templates, and Hate to love them :)

Really, most of the time they are usefull, but once in a while I want to do something with them, and they totally break down and are totally useless.

IMO, C++ would be so much better if it was more consistent. If its namespace was more sane, so you could have proper nested classes, and all that nice stuff. As it is, C++ is severely lacking IMO. Though I do use it. After starting to use Qt regularly, I find myself using C++ even when not using Qt.

I guess I just like the added syntax sugar. But C++ needs allot of improvement. :(

I've also heard tons of good things about C# from many people I trust, but I just don't know if I can switch to it at this point, I don't do windows coding, and I don't have a legal licence ;) who knows if the linux C# compiler supports all I want it to (Qt for one).

Steve++
Quote:

I don't do windows coding, and I don't have a legal licence ;)

Visual C# Express is free and legal.

Thomas Fjellstrom
Quote:

Visual C# Express is free and legal.

But Vista won't be in a year once my free beta licence runs out :P

Steve++

Meh... I haven't had a legitimate windows since 3.11.

Thomas Fjellstrom

Thats nice, I'd rather not develop some possible commercial software on illicit software ;)

That and Vista really isn't good enough to convince me to switch back.

nonnus29

Has anyone else read this guy? Do his ideas have merit? Or are we doomed to eternally debate the merits of general purpose language X vs language Y? Personally, I hope there's a better way....

Thomas Fjellstrom

That dude used the word Paradigm, therefor I shall ignore any thing he has to say. Since its all likely repetitive "Think outside the box" crap.

Steve++

This is the idea behind LOP: Write each module in a domain-specific language. If you don't know that language, spend time learning it. If a good-enough domain-specific language doesn't exist, spend time creating one. This is supposed to save time. Riiight...

axilmar
Shawn Hargreaves said:

The point is not that it is impossible, but that it is much harder to get right.

So in the real world (the world of tools I can actually download and use today, rather than theoretical ones that haven't been written yet) it turns out that there are far more refactoring tools for Java and C# than there are for C++, and these have much richer features and are more robust.

The reason Java as more refactoring tools is that Java uses inheritance of classes and interfaces much more than in C++, and not because it is more difficult to do it in C++.

Quote:

It depends on the feature. Some things are fine in libraries, but others can benefit from dedicated language support for many possible reasons:

  • Better error reporting.

  • More efficient code generation.

  • Nicer syntax.

It certainly depends on the feature...but if it covers those qualities you mention as a library implementation, then it is much preferrable than in the language.

Quote:

Not a huge difference, but the C# version is slightly more concise, and more importantly, less error prone because the braces are enforced as part of the construct, rather than just relying on scoping rules to release the lock at the right place.

The C++ is not error prone at all...it is just as bulletproof as the C# version. The positioning of braces has nothing to do with correctness, as the two implementations are equal.

I will dare say that the C++ version is better, because it allows for much less indentation levels. It is common in C# and Java to write code beyond 4 identation levels, and it gets stupid after a while.

Plus the C++ idiom works for many things like mutex release, file close, handle destruction, so as that the programmer does not have to learn 2 idioms...where as in Java and C# one has to learn synchronization using 'lock' or 'synchronize' (that's idiom #1) and releases resources in 'finally' clauses or at the end of the function (that's idiom #2).

Quote:

Another example is lambda functions. boost::lambda does an amazing job of implementing them in a library, but has lots of corner cases that can be very confusing in practice. Nowhere near as clean and easy to understand as the C# delegate syntax.

Lambdas and delegates are two completely different things. Lambda functions are anonymous functions that are created at the point of their declaration and used as objects, whereas delegates are containers of methods. You should have compared C# delegates to libsig++ or Qt signals. To put it with code:

//fictional C++ lambdas
template <class T, class F> void map(container<T> &con, const F &fun);
list<int> list1;
map(list1, void (list<int>::iterator &t) { cout << *t; }

//delegates ala libsig++
signal<int, float> += slot(foo, &Foo::action1);

With operator overloading, C++ can have delegates just as C#. You are right though that lambdas need support from the language, because in C++ code can not be treated as data.

Quote:

You are mistaken about how C# generics work, and are describing the Java implementation here. C# generics do not cause any unneccessary boxing

Sorry, my bad. According to this, the JIT compiler creates a different instance of a template according to its data type...much like in C++, but in C# the template instance will not actually be created until needed. For me, they are equal, and C++ 'bloat' is not something that affects the applications I write. Of course, the situation could be better, but it's not that critical, considering all the other benefits of C++.

Quote:

But also, the C++ template system makes it hard to give good error messages, as witnessed by the fact that no C++ compiler which actually exists today can come anywhere near the clarity of the errors you get from misusing generics in C# or Java.

The reason that you get clearer error messages in C#/Java is because of constraints: if your template argument does not implement the constraint, then the compiler says that 'foo does not implement bar' or something similar...whereas in C++ there is an error message that points inside the template class, which is difficult to trace (especially if there are many typedefs of template types etc). But, again, this is something not critical, in my opinion. Personally (I must emphasize it because other people may not have a similar experience) I never had any serious problem with the C++ error messages for templates, even in MSVC 6.0.

Quote:

But I'm also aware that they have a lot of issues, high on the list being that a lot of people just don't understand them (which is not aided by generally poor error reporting). So if I'm writing a library that I intend to be used by a wide audience, heavy reliance on templates is probably not a great idea. Generics do much better in that regard. The typical idiot Visual Basic programmer who barely knows enough to string together a couple of forms for his business would be totally lost if you handed him a template API, but can generally get on ok with using generic container types.

I do not see how the type of programmer you mention can not get lost with generic container types while he will get lost with C++ templates. A List<T> and std::list<T> is almost the same thing...the programmer you mention will probably choke on both. The typical idiot Visual Basic programmer most probably should not touch generics/templates in either language.

Personally I do not see why C++ template error reporting shall be so bad. An error message for a template should be reported at the place of instantation, not at the place of declaration, if the error concerns a template parameter. For example, if I write the following code:

template <class T> class Map {
    ...
    if (x < y)
    ...
};

class Foo {
};

Map<Foo> map1;

then I expect the compiler to tell me that "Foo does not define operator < at declaration of 'map1'", for example, and it is dead easy to do (why it is not done, it is beyond me; most probably those C++ compiler writers have much higher decryption capabilities).

Zaphos said:

That feature just calls "make" whenever you save, and isn't recommended. The Eclipse CDT manual, right in the "before you begin" section, states: "For C/C++ projects this feature should be turned off, otherwise builds will be performed whenever a file is saved, including makefiles and header files."

I do not know the exact implementation, but I have hapilly used autocompile with the Eclipse C++ plugin...albeit for small projects, using gcc and precompiled headers. And from what I remember, it compiles the file you save, but not other files.

But again, it is not a language issue per se, but more of an environment issue. You can have an interpreted C++, if you like interactive development (disclaimer: haven't tried it).

You can also try an online C++ compiler here which can emit bytecode if you like.

Zaphos
Quote:

Of course refactoring is technically doable in C++: you can always write a program to programmatically manipulate code written in any well defined language.

Hmm, really? Seems refactoring can get confusing when you allow for complex macros on top of the a language, since we need to consider how the code would expand for any possible set of inputs to those macros, not just those inputs the compiler will see on the current build system. I would worry that those macros might have the ability to take what looks like a clean refactor &, for some input, make the refactor unclean. After all, we have a lot of trouble automatically proving anything at all about programs ... given a well defined but powerful macro language, I imagine the same difficulties would arise. Essentially: how can you refactor if you can have arbitrary-sized blocks of code which may essentially expand to anything at all, as far as you know?
As a more practical concern, here: In a portable, complex C/C++ project we can easily get many different possible code paths pending the macro settings -- are we in debug mode? which compiler are we using? which version of that compiler? which platform are we on?
These code paths may interlace freely, and some will be mutually exclusive, and some won't. At any given time we need to ensure that ALL valid code paths (not just the current one!) remain valid, but we may ignore invalid code paths (these need not compile). Can we really say that will never confuse a refactoring tool? I think the best it could do is to try going through each possible code path, assuming each is valid, and coming back crying if any of them don't make sense. (it's not even clear this is possible, if we can generate code paths based on possible future compiler settings ... going further toward the 'worst case' nightmare fantasy, could we have infinite possible code paths?)

And for a very specific example (not necessarily exhibiting the same problems): if you have something like

#define makevar(N) int var##N
...
makevar(A);
cout << varA;

then you rename "varA" to "foo" ... what is the refactorer supposed to do? Probably 'makevar' was intended to be extensible with more serious initialization in the future -- it would be rather harsh to just replace the macro call to "makevar(A)" with "int foo". And if we changed the behavior of the makevar macro, that's almost certainly a side effect the code author did not expect or intend, and will lead to confusing when they try to make a different variable with makevar (and end up just getting foo back!). So it seems like all the refactorer safely do is fail to refactor.

edit:

Quote:

The reason Java as more refactoring tools is that Java uses inheritance of classes and interfaces much more than in C++, and not because it is more difficult to do it in C++.

This seems incredibly unlikely, especially when presented as the (sole, absolute) reason.

axilmar
Zaphos said:

Hmm, really? Seems refactoring can get confusing when you allow for complex macros on top of the a language, since we need to consider how the code would expand for any possible set of inputs to those macros, not just those inputs the compiler will see on the current build system.

I am not denying that the preprocessor does not make refactoring difficult. My claim is that refactoring is not a commonly used operation in the C++ world because there aren't so many occasions that it is needed. It is very common in the Java world to change the class hierrachy, interfaces, etc, whereas in C++ it is not that common (not so common that the text replacement does not cover).

nonnus29
Quote:

This is the idea behind LOP: Write each module in a domain-specific language. If you don't know that language, spend time learning it. If a good-enough domain-specific language doesn't exist, spend time creating one. This is supposed to save time. Riiight...

SQL is a domain specific language, so that doesn't save time? Riiight... ;)

For a suitably large domain dsl's make perfect sense. I guess the thing that holds them back is there aren't that many large domains. Or the fact developers are too wrapped up in debating meaningless minutia and can't pull back and see the big picture ie look for the domain?

Steve++

The thing is that domain specific languages are exploding all over the place. Look at Java EE. It's covers a domain - a well defined one, but look at how many DSLs it uses.

Shawn Hargreaves
Quote:

Quote:

Another example is lambda functions. boost::lambda does an amazing job of implementing them in a library, but has lots of corner cases that can be very confusing in practice. Nowhere near as clean and easy to understand as the C# delegate syntax.

Lambdas and delegates are two completely different things. Lambda functions are anonymous functions that are created at the point of their declaration and used as objects, whereas delegates are containers of methods.

You're describing what delegates used to be in .NET 1.0.

Modern C# 2.0 delegates are in fact full lambda functions, including lexical scoping.

Quote:

The reason that you get clearer error messages in C#/Java is because of constraints

Exactly! The language has been designed specifically to enable good error messages and make things less confusing.

Quote:

I do not see how the type of programmer you mention can not get lost with generic container types while he will get lost with C++ templates. A List<T> and std::list<T> is almost the same thing...the programmer you mention will probably choke on both. The typical idiot Visual Basic programmer most probably should not touch generics/templates in either language.

Tell that to the literally millions of idiot Visual Basic programmers who are happily churning out code using "List(of String)" or "Dictionary(of String, Wibble)"...

They don't write new generic types (in fact they tend not to write new classes much at all), but there are an awful lot of people who are gainfully employed writing simple procedural code to string together those generic library types.

An STL list is equally simple to declare, but the problem with templates comes when you do something wrong. For a skilled programmer this tends not to be obvious, because top class programmers learn by understanding how the entire system works so they can predict how it will behave, but an awful lot of people don't learn like that. They just try things out, and rely heavily on their IDE and compiler error messages to tell them what they are doing wrong. For someone like this, STL is unusable because when you make a typo using a std::list<>, you get incomprehensible gibberish back. It really does make a huge difference when the compiler is able to tell them exactly what and where the problem is.

Quote:

Personally I do not see why C++ template error reporting shall be so bad.
...
and it is dead easy to do (why it is not done, it is beyond me; most probably those C++ compiler writers have much higher decryption capabilities).

If it's really that easy, why not go write a compiler that does it right? :-)

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

From this you conclude that all existing C++ compiler writers must somehow be stupid, or not trying hard enough, or have failed to notice the problem.

Doesn't it seem even slightly possible that the compiler writers are actually very smart people, and have been working hard on this for over a decade now, but that it it turns out to be an incredibly hard problem?

When presented with a problem hard enough to not have been solved in over a decade, my personal inclination would be to stop throwing myself at the vertical cliff face and try to find an alternative route :-)

axilmar
Quote:

You're describing what delegates used to be in .NET 1.0.
Modern C# 2.0 delegates are in fact full lambda functions, including lexical scoping.

Indeed, but the term 'delegate' is not very appropriate for lambda functions.

Quote:

Exactly! The language has been designed specifically to enable good error messages and make things less confusing.

But constraints are not the desicive factor for good error reporting. I believe that error reporting in C++ templates could be much better, as I already have said.

Quote:

An STL list is equally simple to declare, but the problem with templates comes when you do something wrong. For a skilled programmer this tends not to be obvious, because top class programmers learn by understanding how the entire system works so they can predict how it will behave, but an awful lot of people don't learn like that. They just try things out, and rely heavily on their IDE and compiler error messages to tell them what they are doing wrong. For someone like this, STL is unusable because when you make a typo using a std::list<>, you get incomprehensible gibberish back. It really does make a huge difference when the compiler is able to tell them exactly what and where the problem is.

I think you are overstating the problem. The first time you deal with error messages from C++ templates the report might seem cryptic. But any person deserving the title of programmer should be able to easily comprehend the error message after a while.

Quote:

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

Here is a little situation that usually produces an error message:

1#include <map>
2using namespace std;
3 
4class Foo {
5public:
6};
7 
8class Bar {
9public:
10};
11 
12int _tmain(int argc, _TCHAR* argv[])
13{
14 map<Foo, Bar> map1;
15 map1[Foo()] = Bar();
16 return 0;
17}

The error message is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const Foo'
        c:\program files\microsoft visual studio 8\vc\include\xutility(1842) : see declaration of 'std::operator <'

It is not a difficult to comprehend message is it? I have not written "operator <" for type Foo.

Quote:

From this you conclude that all existing C++ compiler writers must somehow be stupid, or not trying hard enough, or have failed to notice the problem.

I never said they are stupid. What I said is that they haven't addressed the problem because they do not have the problem. It is the same like garbage collection: they can easily code large programs without GC, where the rest of the people are not that capable. Propably because these compiler writers are too smart.

Quote:

Doesn't it seem even slightly possible that the compiler writers are actually very smart people, and have been working hard on this for over a decade now, but that it it turns out to be an incredibly hard problem?

When presented with a problem hard enough to not have been solved in over a decade, my personal inclination would be to stop throwing myself at the vertical cliff face and try to find an alternative route :-)

Really, I do not see how hard it is to infer that a template argument does not implement a particular interface.

Microsoft has already done it, but they prefer to report the details before the actual error. I have just noticed that the last line of the error output is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2676: binary '<' : 'const Foo' does not define this operator or a conversion to a type acceptable to the predefined operator

...which says exactly what the problem is.

Shawn Hargreaves
Quote:

I believe that error reporting in C++ templates could be much better, as I already have said.

I'm sure it will continue to get better. But today it is pretty bad. And you are mistaken in thinking that the compiler writers are not spending time on this problem: it is actually being taken very seriously and a lot of work is going into how to improve things. It just happens to be a really hard problem.

I can't tell you exactly what the hard bits are, having never written a C++ compiler myself, but I'm inclined to believe those who have when they tell me this turns out to be extraordinarily difficult!

Quote:

I think you are overstating the problem. The first time you deal with error messages from C++ templates the report might seem cryptic. But any person deserving the title of programmer should be able to easily comprehend the error message after a while.

Ah yes, the "programming is hard, so programmers need to be clever" argument. Yes, it's true, after a while a clever person can comprehend all sorts of stuff. But does that mean we should just give up and settle for what we have today? I think not. In an ideal world people shouldn't have to spend time getting used to things that seem cryptic, and I think we should strive toward that ideal world.

There are two possible ways to improve cryptic error messages: improve the compiler, or improve the language.

You seem convinced that a better compiler could make the whole problem go away, but I just don't see that. Smart people have tried to write this compiler, and failed. Maybe they will figure it out next year, but maybe not. I'm not betting on it. From a practical perspective, that better compiler certainly does not exist today.

Wheras better languages do exist today. Several of them. You can download them and use them for free.

I'm a practical guy, and from a practical perspective, it seems a lot less risky to go with the solution that has been proven to work, rather than one that you think might be possible in the future (especially when the people who actually write the compilers disagree).

Quote:

The error message is:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2784: 'bool std::operator <(const std::reverse_iterator<_RanIt> &,const std::reverse_iterator<_RanIt2> &)' : could not deduce template argument for 'const std::reverse_iterator<_RanIt> &' from 'const Foo'
        c:\program files\microsoft visual studio 8\vc\include\xutility(1842) : see declaration of 'std::operator <'

It is not a difficult to comprehend message is it?

Are you kidding?

That's a TERRIBLE error message!

What is xutility?
What is functional?
What is a reverse_iterator?
What is std:: operator <?

I'm not using any of those in my code! Stupid compiler is giving me random errors from some code that I'm not even calling. Must be a compiler bug.

What does that even mean "could not deduce template argument"?

What, you mean I have to write a less than operator before I can use a type in a map? Nobody told me that!

So where does std:: operator< come in? How is that related to the < operator I normally use in my code?

You have to know a lot about both C++ and the STL implementation to decode this stuff.

A good error message would be:

"Cannot store Foo in a map because Foo does not implement operator <"

But no existing C++ compiler can come within a million miles of telling me that.

C#, on the other hand, can tell me exactly what the mistake is:

using System;

class Container<Key, Value> where Key : IComparable<Key> { }

class Foo { }

class Test
{
    public Test()
    {
        Container<Foo, string> container;
    }
}

t.cs(15,9): error CS0309: The type 'Foo' must be convertible to 'System.IComparable<Foo>' in order to use it as parameter 'Key' in the generic type or method 'Container<Key,Value>'

GullRaDriel

What a debate !

23yrold3yrold
Quote:

Fact: all existing C++ compilers give terrible error messages for mistakes involving templates.

"Fact" is right.

Quote:

That's a TERRIBLE error message!

And I've seen much, much worse. :) I've always wondered why the C++ compiler can't speak plain English for errors like that ...

Goalie Ca

Trying to understand error strings in a library as complicated and as templated as itk [1] is impossible. Luckily you can generally figure it out by looking at the line number and thinking.

[1]http://www.itk.org/

C# is quite a fine language for programming everyday desktop applications. Memory management needs a little help and for speed reasons it should almost always link with a native library but other than that, its quite fine.

C++ is the only real general purpose language here. C++ is good at most things and excels at the rest. C++ needs a bit of work and a whole bunch of libraries (but c# needs a whole bunch of libraries).

Marcello

I think template errors are best when you're not even using templates, but just something normal, like strings.

Marcello

axilmar
Quote:

I'm sure it will continue to get better. But today it is pretty bad. And you are mistaken in thinking that the compiler writers are not spending time on this problem: it is actually being taken very seriously and a lot of work is going into how to improve things. It just happens to be a really hard problem.

I have to disagree about 'pretty bad'. It is not as good as it is supposed to be, but it is nowhere near as 'bad'.

Quote:

I can't tell you exactly what the hard bits are, having never written a C++ compiler myself, but I'm inclined to believe those who have when they tell me this turns out to be extraordinarily difficult!

The reason I believe the problem is not as difficult as we are being told is because I tried to solve it with a test compiler I wrote explicitely for that some moons ago.

The problem can be described like this:

"If I find that a type does not implement an operation, within a template class, what do I do? is it the template erroneously implemented or the template instantiation is wrong?".

The solution is pretty easy: the compiler knows the exact type of the operand, and it also knows where the template instantiation is. That is the reason all the compilers can finally say that the problem arises at the specific line the template class is instantiated.

Even in the case that the template class instantiates other template classes with the same parameters, even if the type is passed through a typedef, it is still possible to say where the error is, and this is demonstratable from the 'map' example I gave you earlier: all compilers will show the line of the map instantiation as the line the error comes from.

To put it with symbols: suppose you have a type K[T] which uses types K1[T], K2[T] etc where Ks are the template classes and T is the template type. At any position within a template class, the template instantiation forms a tree where root is the first class that T is passed to: K[T] -> K1[T] -> K2[T] etc. Therefore, in order to show a comprehensible error report is to start the error report from the root of the tree and not from its edges.

I hope you understand after this analysis that the problem of template error reporting is very much an implementation issue rather than a language issue.

Quote:

Ah yes, the "programming is hard, so programmers need to be clever" argument. Yes, it's true, after a while a clever person can comprehend all sorts of stuff. But does that mean we should just give up and settle for what we have today? I think not. In an ideal world people shouldn't have to spend time getting used to things that seem cryptic, and I think we should strive toward that ideal world.

I agree with you, but in the quest to find the ideal we should not give up what we have today, if it is possible. I prefer to fix C++ (because it is doable) rather than to give up its goodies for a dumbed down version called C#.

Quote:

Are you kidding?

That's a TERRIBLE error message!

What is xutility?
What is functional?
What is a reverse_iterator?
What is std:: operator <?

Ok, I admit it is not a perfect message, but the reason it is not a perfect message is because the compiler writers preferred connecting the operators provided by STL to the user-defined types, which is totally silly. If an operator is not specified for a type, and a conversion to another type is not possible, then the user should not see that the compiler failed to identify a conversion.

But the message above is not the last line. The last line of the error message is much better:

c:\program files\microsoft visual studio 8\vc\include\functional(143) : error C2676: binary '<' : 'const Foo' does not define this operator or a conversion to a type acceptable to the predefined operator

Again, it is not a perfect message, but as you can see the compiler prints the desired information. At another line, the compiler prints the error line:

test1.cpp(18) : see reference to class template instantiation 'std::map<_Kty,_Ty>' being compiled

Which means that:

1) the compiler knows the real source of error.
2) the compiler knows the exact problem.

Therefore the compiler could easily have said:

test1.cpp, line 18: operator < not defined for class Foo

So template error reporting is an implementation issue after all.

Quote:

C#, on the other hand, can tell me exactly what the mistake is:

using System;

class Container<Key, Value> where Key : IComparable<Key> { }

class Foo { }

class Test
{
public Test()
{
Container<Foo, string> container;
}
}

t.cs(15,9): error CS0309: The type 'Foo' must be convertible to 'System.IComparable<Foo>' in order to use it as parameter 'Key' in the generic type or method 'Container<Key,Value>'

There is also lots of information that one needs to know:

1) what does it mean to 'be convertible to'?
2) what is System?
3) what is 'I' in front of the comparable?
4) what is 'Comparable'?
5) how is 'Comparable' handled?
6) why Container<Key,Value> may be a method?

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

With C#, I have to do a lot more:

1) I have to lookup the documentation of IComparable.
2) I have to modify my class to implement IComparable.
3) if I do not have the source, I have to make a wrapper class for 'Foo' which contains/extends Foo and implements IComparable, and load the runtime with extra objects.

What if I want my key to be a primitive? the Container class becomes complicated then. Does C# support template specialization? if it does not, then primitive keys would have to be boxed in order to be used as keys, and thus the advantage of using primitives is lost. If C# does support specialization, then one has to write a two implementations of comparison, one for primitives and one for IComparables.

Shawn Hargreaves
Quote:

The solution is pretty easy: the compiler knows the exact type of the operand, and it also knows where the template instantiation is. That is the reason all the compilers can finally say that the problem arises at the specific line the template class is instantiated.

That logic works fine until you have templates of templates. It can only find the outermost point of the instantiation which failed, not the specific point where a type that was ok transitions to a type that violates a constraint. Templates of templates aren't that uncommon, especially in code that uses smart pointers, strings, and the pair type.

Also, this only tells you where the problem happened, not what went wrong, which is really where the errors fall down. Determining what went wrong is not as simple as just reporting what method or operator call wasn't implemented, because STL (or any modern C++ library) uses a lot of partial specialization tricks that obscure this. Type traits, iterator traits, etc, make it impossible to figure out what's going on when you do things like try to instantiate a random iterator container on a type that only provides input iterators.

Quote:

There is also lots of information that one needs to know:

1) what does it mean to 'be convertible to'?
2) what is System?
3) what is 'I' in front of the comparable?
4) what is 'Comparable'?
5) how is 'Comparable' handled?
6) why Container<Key,Value> may be a method?

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

Now that's not fair! If you're allowed to say it is common knowledge how operator < works in C++, then you have to grant me that it is also common knowledge how IComparable works in C#.

But there is actually a big difference between the required knowledge to understand the C# error message versus the C++ one. All the terms in the C# error directly relate either to the container type, the type I tried to store in the container, or the interface which I should have implemented to make this work. In other words every one of these terms is something that I need to know, or if I don't know, I need to go look up.

Whereas in the C++ error message, there are too many terms which have nothing to do with my code. It is leaking STL implementation details which I ought not to have to know about. I wanted to store a Foo in a std:: map, and this failed because Foo has no operator <, but the error message refers to reverse_iterator, xutility, functional, and std:: operator <. I actually do happen to know what those are because I've been using STL for years, but I shouldn't need that knowledge just to construct a basic map.

Quote:

With C#, I have to do a lot more:

1) I have to lookup the documentation of IComparable.
2) I have to modify my class to implement IComparable.

And in what way is this different to the C++ guy who has to look up the documentation for operator <, and modify their class to implement it?

Quote:

What if I want my key to be a primitive?

All the primitive types already implement IComparable: they wouldn't be comparable, otherwise!

Thomas Fjellstrom
Quote:

At least with C++, it is common knowledge of how "operator <" works: it takes two arguments and returns a bool.

It sure as hell isn't common knowledge. I haven't yet found ONE good resource that lists all of the standard operator overload formats, and explains how and why to use them. NOT ONE.

Matt Smith

Everyone has only mentioned text-based languages.

I think the class-hierarchy diagramming part of UML is the way forward.

And operator overloading will only make sense when the full Unicode set is allowed ;)

nonnus29
Quote:

I think the class-hierarchy diagramming part of UML is the way forward.

I read a book were the guy was talking about specifying lexers and parsers using uml style diagrams and made the case that visually specifying languages was the way of the future. Damn if he didn't have text embedded in the diagrams describing the abstract syntax though.

The big problem with uml and all other design and documentation tools is that they're separate from the actual implementation so when developers change a bad or poorly thought out design when they're coding theres no change in the documentation unless they go back and change it. And we all know how programmers love to maintain documentation.

Another factor is that visual languages can always be reduced to a text representation. There's an abundance of tools for manipulating string of characters, but not so many for manipulating graphical diagrams.

Matt Smith
Quote:

abundance of tools

That's the only problem. UML tools are generally free & crap or uberexpensive and untested (by me)

The same goes for programmable diagramming tools which can be coerced into doing UML e.g. Dia (free and crap), and Visio or Flash MX (expensive)

I'm writing my own. It has only cost me 6 years (on and off) so far.

Goalie Ca
Quote:

I think the class-hierarchy diagramming part of UML is the way forward.

Hells no! This is why i hate those people who study software engineering in grad school. They have no idea what all the other programmers who don't write databases/information systems do for a living. These other systems aren't perfect and could use some love and attention (esp since far more everyday people need to write code to do their thing than exist software engineers with a CS degree).

Ironically the people who have it figured out the best are the systems engineers. PLC ladder logic. So simple you can have any electrician draw a diagram that controls 1000's of inputs and 1000's of outputs with super rediculous reliability and no race conditions or deadlocks. There's a reason why its used everywhere including power plants, factories, and even buildings (lighting and security).

For scientific computing while matlab is nice for ease of use, fortran is nicer because it can actually be used to process data. New standards like f95 now support > and < keywords :D Most numerical/scientific libraries are still written in fortran. UML is useless for scientific people.

Then for the embedded systems designer you have VHDL/Verilog and C/asm/c++. VHDL and Verilog are crazy complex. C and ASM can become tedious and could use some love but we need something low level with a similar paradigm in mind to replace it. Even the java micro environment is a pain in the ass to work with. Compile once my ass and its a resource hog. I wouldn't use it for anything real time ever ever ever.

Business and psych use SPSS stats packages. There's a nice gui application but it can never just do everything people want. i know that you can script it with python. I'd assume that all the numerical stuff though is written in fortran.

In my experience CS researchers seem to focus on OOP and there are a few "old-farts" who look at functional programming and maybe a nut ball that looks at something completely different (like category theory). Like i said, OOP and those tools are fine for writting information systems and maybe even desktop applications and such but there's sooooo much programming which goes on outside of that rather small realm.

axilmar
Quote:

That logic works fine until you have templates of templates. It can only find the outermost point of the instantiation which failed, not the specific point where a type that was ok transitions to a type that violates a constraint. Templates of templates aren't that uncommon, especially in code that uses smart pointers, strings, and the pair type.

No, it is not a problem. As I have shown in the example that uses 'std::map', which uses 'std::pair' and a host of other classes, the compiler knows exactly the outtermost error position and the exact type of error.

Quote:

Also, this only tells you where the problem happened, not what went wrong, which is really where the errors fall down. Determining what went wrong is not as simple as just reporting what method or operator call wasn't implemented, because STL (or any modern C++ library) uses a lot of partial specialization tricks that obscure this. Type traits, iterator traits, etc, make it impossible to figure out what's going on when you do things like try to instantiate a random iterator container on a type that only provides input iterators.

Again, the compiler knows the exact position of error and the types involved.

Quote:

Now that's not fair! If you're allowed to say it is common knowledge how operator < works in C++, then you have to grant me that it is also common knowledge how IComparable works in C#.

Not really. Operator < works the same across all languages (except Lisp and its variants): it is an infix operator that accepts two arguments and returns true/false. Whereas IComparable could be coded in many different ways, with many different function names and maybe different return types.

Quote:

But there is actually a big difference between the required knowledge to understand the C# error message versus the C++ one. All the terms in the C# error directly relate either to the container type, the type I tried to store in the container, or the interface which I should have implemented to make this work. In other words every one of these terms is something that I need to know, or if I don't know, I need to go look up.

Whereas in the C++ error message, there are too many terms which have nothing to do with my code. It is leaking STL implementation details which I ought not to have to know about. I wanted to store a Foo in a std:: map, and this failed because Foo has no operator <, but the error message refers to reverse_iterator, xutility, functional, and std:: operator <. I actually do happen to know what those are because I've been using STL for years, but I shouldn't need that knowledge just to construct a basic map.

I agree with your point, but I disagree on the part that says it is the language's fault. I think it is an implementation issue, not the language's fault.

Quote:

And in what way is this different to the C++ guy who has to look up the documentation for operator <, and modify their class to implement it?

First of all, you do not need to look up the documentation for operator <, because it is common knowledge. When you get to the point of using a map, you already have used operator < in an if statement at least once in your life.

Secondly, you do not need to modify the class; you can provide the operator function externally. That's very handy when you do not have the source.

Quote:

All the primitive types already implement IComparable: they wouldn't be comparable, otherwise!

I do not understand how primitives can implement an interface; primitives are not objects, they do not have a vtable, so how is it possible to implement IComparable?? It is either that a) the compiler cheats and provides an intrinsic implementation of IComparable or b) primitive values are boxed into objects, thus loosing the advantage of using primitives in generics.

Furthermore, if you do a 'x < 3', is the IComparable interface invoked or not?

nonnus29
Quote:

That's the only problem. UML tools are generally free & crap or uberexpensive and untested (by me)

The same goes for programmable diagramming tools which can be coerced into doing UML e.g. Dia (free and crap), and Visio or Flash MX (expensive)

I'm writing my own. It has only cost me 6 years (on and off) so far.

In my opinion, a programming language can't be entirely graphically, or you'd end up with insanely complex flowchart (lego mindstorms has a graphically language, I've never seen it though) for any nontrivial application. Plus using uml is bad idea because it's to ambiguous to generate actual programs from. Sure you can generate skeleton classes, but that's about 1% of the problem.

My idea is to combine a visual model of a finite state machine and attach code to the nodes to perform actions and code to the edges to specify the conditions for transitions between states. The language used for the code part could be any language that the tool would massage into shape when the 'generate source code' button is pushed (hey, I didn't say it was a good idea...).

Quote:

Hells no! This is why i hate those people who study software engineering in grad school. They have no idea what all the other programmers who don't write databases/information systems do for a living.

I hate those guys too, there's nothing like someone who's never worked as a professional programmer telling you about a new pattern he just 'discovered'. But the truth is, there are ALOT of database driven applications around (the internet) and thats were alot of money's at (financial services).

Matt Smith
Quote:

or you'd end up with insanely complex flowchart

only when fully expanded. My prog has the graphic equivalent of code folding. And yes, at the bottom level you do have text, but then all good diagrams are correctly and clearly labelled ;)

Shawn Hargreaves
Quote:

No, it is not a problem. As I have shown in the example that uses 'std::map', which uses 'std::pair' and a host of other classes, the compiler knows exactly the outtermost error position and the exact type of error.

But it doesn't know the outermost error position at all. It knows the outermost point of the template instantiation. In your example that is the same as the point of the error, but that isn't always the case.

Quote:

Quote:

Now that's not fair! If you're allowed to say it is common knowledge how operator < works in C++, then you have to grant me that it is also common knowledge how IComparable works in C#.

Not really. Operator < works the same across all languages (except Lisp and its variants): it is an infix operator that accepts two arguments and returns true/false. Whereas IComparable could be coded in many different ways, with many different function names and maybe different return types.

Huh?

C++: bool operator < (T a, T b);

C#: int IComparable<T>.CompareTo(T other);

Perl: use overload '<' => 'MyCompare';

Python: def __cmp__(a, b):

Ruby: def <(other)

Out of five languages that immediately occured to me, I'm not seeing a huge amount of commonality.

C# and Ruby have the compare as an instance method taking one argument, while in the other three it takes two arguments.

C# and Python return an strcmp style integer encoding less, equal, or greater, while the other three return a boolean and use a different method for greater than comparisons.

In fact the only two that work the same are C++ and Perl, but that's only because I left out all the other wacky Perl comparison operators that you'd probably want to overload as well.

I think the only really safe generalization is that you have to know the correct way to overload operators in your language of choice, because each one is different!

Quote:

Quote:

And in what way is this different to the C++ guy who has to look up the documentation for operator <, and modify their class to implement it?

First of all, you do not need to look up the documentation for operator <, because it is common knowledge.

Sorry, but that's just a ridiclous thing to say.

You know how to overload operator < in C++, sure. So do I, but not everyone does.

Some people know how to overload IComparable in C#, too. I do, for instance, but you do not.

It's just crazy to say that one is common knowledge while the other is not, unless you're going to add some qualification like "this is common knowledge among the set of expert C++ programmers who have encountered a need to provide custom operator overloads at some earlier point in their career".

Quote:

Quote:

All the primitive types already implement IComparable: they wouldn't be comparable, otherwise!

I do not understand how primitives can implement an interface; primitives are not objects, they do not have a vtable, so how is it possible to implement IComparable??

You don't need a vtable to implement interfaces in C#. The compiler is clever, and the .NET type system is very clever. You're assuming it works like Java, which isn't at all the case.

Quote:

It is either that a) the compiler cheats and provides an intrinsic implementation of IComparable or b) primitive values are boxed into objects, thus loosing the advantage of using primitives in generics.

No boxing, and no cheating. You just implement whatever interface you like and off you go.

Quote:

Furthermore, if you do a 'x < 3', is the IComparable interface invoked or not?

Yes, but whether this is statically or dynamically resolved depends on the type of X, and whether the interface implementation is virtual or not. Very much like in C++, actually, where you might or might not choose to make operator < virtual.

Evert
Quote:

Operator < works the same across all languages

FORTRAN prior to FORTRAN '95?

Thomas Fjellstrom
Quote:

First of all, you do not need to look up the documentation for operator <, because it is common knowledge.

You totally decided to ignore what I said didn't you?

I'll quote it here for you: (since you seem to be ignoring half or all of what most people are saying here, and stubbornly refusing to consider that you might possibly be wrong.)

I said said:

It sure as hell isn't common knowledge. I haven't yet found ONE good resource that lists all of the standard operator overload formats, and explains how and why to use them. NOT ONE.

Goalie Ca

I'm dumb! i believe the operator exists just uses a different symbol...

If (x .lt. 5) then 
   x = 7
else
   x = 9
end if

nonnus29

In one of the scripting languages I use at work LT, LE, GT, GE, NE and EQ are all valid comparison operators in addition to < , > , =, etc...

Everyone who's sick of the template error message argument, clap your hands.

::)

Quote:

only when fully expanded. My prog has the graphic equivalent of code folding. And yes, at the bottom level you do have text, but then all good diagrams are correctly and clearly labelled ;)

Interesting....

_Dante
Quote:

Everyone who's sick of the template error message argument, clap your hands.

589702

Goalie Ca

you mean like this...
The error is not what it says... Not by a long shot.
Earlier had tons of non-sensical errors mostly because of typedefs and shit being broken on just about every compiler.

#SelectExpand
1Volume.cpp:360: error: invalid initialization of non-const reference of type ‘rysci::Volume3D<boost::array<double, 3ul> >&’ from a temporary of type ‘rysci::Volume3D<boost::array<double, 3ul> >* 2Volume.cpp: In copy constructor ‘rysci::Volume3D<T>::Volume3D(const rysci::Volume3D<T>&) [with T = boost::array<double, 3ul>]: 3Volume.cpp:414: instantiated from here 4Volume.cpp:117: error: passing ‘const rysci::Volume3D<boost::array<double, 3ul> >’ as ‘this’ argument of ‘T& rysci::Volume3D<T>::operator[](const size_t&) [with T = boost::array<double, 3ul>]’ discards qualifiers 5Volume.cpp: In function ‘void rysci::IO::writeVtk(std::string, const rysci::Volume3D<T>&) [with T = boost::array<double, 3ul>]: 6Volume.cpp:416: instantiated from here 7Volume.cpp:378: error: passing ‘const rysci::Volume3D<boost::array<double, 3ul> >’ as ‘this’ argument of ‘const rysci::VolAttribs<3ul>& rysci::Volume3D<T>::attribs() [with T = boost::array<double, 3ul>]’ discards qualifiers 8Volume.cpp:416: instantiated from here 9Volume.cpp:382: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 10/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 11/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 12/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 13/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 14/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 15/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:182: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 16/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:190: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 17/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.h:2045: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 18Volume.cpp:382: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 19/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 20/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 21/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 22/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 23/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 24/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:182: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 25/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:190: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 26/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.h:2045: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 27Volume.cpp:382: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 28/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 29/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 30/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 31/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 32/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 33/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:182: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 34/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:190: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 35/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.h:2045: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 36Volume.cpp:383: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 37/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 38/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 39/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 40/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 41/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 42/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:182: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 43/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:190: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 44/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.h:2045: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 45Volume.cpp:383: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 46/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 47/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 48/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 49/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 50/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 51/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:182: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 52/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:190: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 53/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.h:2045: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string() [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 54Volume.cpp:383: error: no matching function for call to ‘std::basic_string<char, std::char_traits<char>, std::allocator<char> >::basic_string(double&) 55/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:232: note: candidates are: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(typename _Alloc::size_type, _CharT, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 56/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:225: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 57/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:218: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 58/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:207: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type, const _Alloc&) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 59/usr/lib/gcc/x86_64-linux-gnu/4.0.3/../../../../include/c++/4.0.3/bits/basic_string.tcc:196: note: std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const std::basic_string<_CharT, _Traits, _Alloc>&, typename _Alloc::size_type, typename _Alloc::size_type) [with _CharT = char, _Traits = std::char_traits<char>, _Alloc = std::allocator<char>] 60 61... goes on post too long...

Evert
Quote:

i believe the operator exists just uses a different symbol...

Ofcourse a comparison operator exists; the language would be pretty useless without it (I actually program in FORTRAN nearly everyday at work). However, it's not written <, so saying `Operator < works the same across all languages' is strictly false, sine FORTRAN 77 doesn't have a < operator.
(Aside: yes, you can argue that people should not code to a language specification that is 30 years old and obsolete; factis that people do).

axilmar
Shawn Hargreaves said:

But it doesn't know the outermost error position at all. It knows the outermost point of the template instantiation. In your example that is the same as the point of the error, but that isn't always the case.

The top-level of a C++ program is not a template; therefore the compiler starts in non-template mode. At some point the compiler finds a template instantiation and tries to compile it; from that point on, the compiler knows exactly where the types are given and what is the outtermost point that a type was instantatiated, even if typedefs are used.

Quote:

Huh?
C++: bool operator < (T a, T b);
C#: int IComparable<T>.CompareTo(T other);
Perl: use overload '<' => 'MyCompare';
Python: def __cmp__(a, b):
Ruby: def <(other)

Thanks for the examples that show how broken most languages are. These languages all use operator < for comparison in expressions, but only some of them are consistent enough to use it in collections.

Quote:

Out of five languages that immediately occured to me, I'm not seeing a huge amount of commonality.

C# and Ruby have the compare as an instance method taking one argument, while in the other three it takes two arguments.

C# and Python return an strcmp style integer encoding less, equal, or greater, while the other three return a boolean and use a different method for greater than comparisons.

In fact the only two that work the same are C++ and Perl, but that's only because I left out all the other wacky Perl comparison operators that you'd probably want to overload as well.

I think the only really safe generalization is that you have to know the correct way to overload operators in your language of choice, because each one is different!

My point was not about how languages handle operator overloading, but how all languages use operator < in expressions. Your cleverly talked about the operator overloading, but I talked about what operator < is and how it is used in expressions.

All languages except LISP and those with reverse polish notation handle operator < like this (ok, and maybe a few others, but if you want to nitpick):

<argument1> '<' <argument2>

so it is pretty much common knowledge on how this operator is supposed to work. And it is a step in the right direction when a language allows an operator to be defined 'naturally', i.e. in the same manner that it used.

Quote:

Sorry, but that's just a ridiclous thing to say.

You know how to overload operator < in C++, sure. So do I, but not everyone does.

Some people know how to overload IComparable in C#, too. I do, for instance, but you do not.

It's just crazy to say that one is common knowledge while the other is not, unless you're going to add some qualification like "this is common knowledge among the set of expert C++ programmers who have encountered a need to provide custom operator overloads at some earlier point in their career".

Not as ridiculus as twisting one's argument, I am afraid.

Quote:

You don't need a vtable to implement interfaces in C#. The compiler is clever, and the .NET type system is very clever. You're assuming it works like Java, which isn't at all the case.

I already told you the compiler cheats.

Quote:

No boxing, and no cheating. You just implement whatever interface you like and off you go.

Of course it is not boxing, but it is cheating. Because the language does not treat classes uniformly. Of course in C# primitives are structs, but that is a completely artificial distinction (between structs and classes, that is).

Of course that introduces another problem: what if I have a very useful struct that I want it to leave on the heap, for some reason? C# bites the bullet, doesn't it? the programmer has to make a wrapper class (as always, feel free to correct me - I am not a C# expert; C# has many hidden corners). Whereas in C++ the memory space a variable lives is decoupled from the actual functionality of the class...and that, my friend, is correct design.

Quote:

Yes, but whether this is statically or dynamically resolved depends on the type of X, and whether the interface implementation is virtual or not. Very much like in C++, actually, where you might or might not choose to make operator < virtual.

If I make my own value class that implements IComparable with a side effect (for example, outputing a message in the console), do I get the message when I do a 'x < 3' or do I have to explicitely call 'CompareTo'?

Thomas Fjellstrom said:

You totally decided to ignore what I said didn't you?

I'll quote it here for you: (since you seem to be ignoring half or all of what most people are saying here, and stubbornly refusing to consider that you might possibly be wrong.)

As usual, it's me vs Allegro.cc...what's up with the sheep mentality anyway?

Look, your comment is covered in some of my replies. Feel free to feel it is unjustified, but don't complain because in a topic with 9 pages I haven't replied to you. Has it occurred to you I maybe did not notice your message? and certainly I am not in a dialogue with half of what people are saying here.

Quote:

It sure as hell isn't common knowledge. I haven't yet found ONE good resource that lists all of the standard operator overload formats, and explains how and why to use them. NOT ONE.

What exactly is it there you want to know? the C++ documentation is pretty clear on how operators are overloaded and there are plenty of articles to check online. And the Microsoft documentation has what you ask (i.e. the list of all operators, their format, if they are binary or unary, and their associativity).

How is it the fault of the language that you can't easily find the documentation you ask? if somebody had bothered to write it, you wouldn't complain. But it is not a fault of the language in any way.

Goalie Ca said:

you mean like this...
The error is not what it says... Not by a long shot.
Earlier had tons of non-sensical errors mostly because of typedefs and shit being broken on just about every compiler.

Maybe the error is that you tried to instantiate an std::string from a double.

Disclaimer for all the people that are interested in this discussion:

I am not saying that C++ error reporting is perfect or even good. What I am saying is that the compiler creators did not bother implement decent error reporting and that it is not the language's fault that template error messages are not that good. The language, as it is, does not lack anything that makes it impossible to have error reporting as good as other languages created much later (C#, for example).

Thomas Fjellstrom
Quote:

And the Microsoft documentation has what you ask

Because we all run windows and have an MSDN subscription.

Quote:

what's up with the sheep mentality anyway?

Just because people agree doesn't mean they are sheep.

Quote:

the C++ documentation is pretty clear on how operators are overloaded and there are plenty of articles to check online.

_The_ C++ documentation, the one that costs hundreds to thousands of dollars? And hey, if you have a link to a complete table of all the forms of operator overloads, as well as some examples to go with, that'd be great. I've searched many times in the past and not found one.

_Dante

C++ operator overloading

Sorry... couldn't help myself :-/

Marcello

Holy crap, you can overload ,? How does that work?

Marcello

Shawn Hargreaves
Quote:

Holy crap, you can overload ,? How does that work?

This is where the difference between the words "can" and "should" becomes really important :-)

You can overload it to do anything you like. For instance I've seen this used as a container constructor:

- Overload 'T, T' to return a vector<T> containing the two arguments
- Overload 'vector<T>, T' to return a concatenated vector

Then you can write '1, 2, 3, 4' as shorthand for constructing a vector and filling it with data.

Is this actually a good idea?

I suspect not.

Thomas Fjellstrom
Quote:

Sorry... couldn't help myself :-/

And how am I supposed to know that thats actually Standard C++? Does MS even support Standard C++?

Not to mention that the page is virtually unreadable. I suspect they expect me to be using IE, which is certainly NOT the case.

Zaphos
Quote:

I am not saying that C++ error reporting is perfect or even good. What I am saying is that the compiler creators did not bother implement decent error reporting and that it is not the language's fault that template error messages are not that good.

I don't have much to say about the specifics of the argument; I'm not entirely sold on it but I lack both expertise & interest. Interest, because really, as someone who is not a language developer but rather a language user, I find it hard to ignore the context in which the language is presented. The tools and features surrounding a language do matter. Shawn said something interesting in a similar thread, pointing out that even the language 'culture' affects the experience of using the language. As an end user, the quality of the language experience is not determined by just the core specification, but by all sorts of external factors surrounding the language.
It's only in a very abstract context, or from the perspective of someone looking to design new languages, that it seems worthwhile to look at the core of the language alone. And even the language designer needs to look beyond that quite soon after specifying the language -- no one needs a language that's only good in theory.

edits:
Regarding operator overloading, seems to me there are plenty of references around. Here are a few more.
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Table
http://en.wikibooks.org/wiki/Programming:C_plus_plus/V3/Operator_Overloading
http://www.parashift.com/c++-faq-lite/operator-overloading.html
And the MS page read just fine for me, with Firefox. Seemed like a decent reference page.

Marcello

Page loads fine in Firefox.

Marcello

_Dante
Quote:

And how am I supposed to know that thats actually Standard C++? Does MS even support Standard C++?

Much as it pains me to admit it, MSVC is probably one of the most compliant compilers around. Sadly, ARM is somewhat behind; I do embedded development, and one of the guys in my office is a C++ junky. I think he has the spec open in his browser with a lead weight resting on F5. Anyhow, he's always bitching about some missing feature or other. Some people use templates way too much.

Quote:

Not to mention that the page is virtually unreadable. I suspect they expect me to be using IE, which is certainly NOT the case.

I'm using Firefox, and it looks just fine.

Regardless, I was merely pointing out that documentation is both available and free, and really, doing it in jest. I'm up for a good debate as much as the next guy - probably more - provided it doesn't degrade into jumping down each other's throats over minutia like this. We're about one step away from, "Oh yeah? If you love C++ so much, why don't you marry it?"

Thomas Fjellstrom
Quote:

minutia

Might be minutia to you :P

Since firefox started eating up 512MB+ ram, I've switched away.

Quote:

Regarding operator overloading, seems to me there are plenty of references around. Here are a few more.

Thank you. Except none of those links, including the MSDN one comes close to what I asked for. I actually do know about all of the standard operators, just not the forms you need to use in specific instances when overloading them. Many operators have more than one overloaded form depending on the usage/context.

Something like this would be very nice, I'd even print it out, laminate it and tack it to the wall/stick it to my monitor.

 Operator    Form                          Usage
+                 Type  operator+(...)  ....   

Zaphos
Quote:

Except none of those links, including the MSDN one comes close to what I asked for.

The wikibooks one divides the operators into categories and gives usage examples for each category. They skip examples for the [] and () operators, but still explain the usage, and there's more discussion of those two in the c++ faq lite. So while the information might not come in exactly the form you want, it seems to be out there in a relatively extensive and friendly way such that you could put it in that form without excessive difficulty.

Carrus85

If you want a good read on how operator overloads work (as well as other advanced topics), I'd recommend Bruce Eckel's Thinking in C++ books, both volumes. Great books, IMHO.

I had a long post about how to do particular operator overloads from memory, but A) it was eaten by the Flying Spagetti Monster and B) it is probably faster and more easily readable to just direct you to a book that covers it all in depth.

23yrold3yrold
Quote:

Much as it pains me to admit it, MSVC is probably one of the most compliant compilers around.

Wow, things have changed a lot. I still remember after I wrote those STL tutorials; almost every person that had errors compiling them was a VC++ user ...

_Dante
Quote:

Wow, things have changed a lot. I still remember after I wrote those STL tutorials; almost every person that had errors compiling them was a VC++ user ...

They have. VC6 was definitely lacking, but VC7 apparently steps up to the plate. My template loving co-worker does all sorts of wild things and there never seems to be an issue until we pump them through armcpp. It's all down to economics, I guess.

axilmar
Quote:

Because we all run windows and have an MSDN subscription.

It is online.

Quote:

Just because people agree doesn't mean they are sheep.

They agree, but what arguments they have? it seems like they agree because somebody famous said something, not because they have analysed the arguments and found them correct.

Thomas Fjellstrom said:

The C++ documentation, the one that costs hundreds to thousands of dollars? And hey, if you have a link to a complete table of all the forms of operator overloads, as well as some examples to go with, that'd be great. I've searched many times in the past and not found one.

Sorry for saying this, but you remind me of Rantaplan, Lucky Luke's dog: in an area full of water and food, it almost died from starvation.

I won't do your job, google is your friend.

_Dante said:

Sorry... couldn't help myself

Now...you've spoilt it! the fun is gone!!! :-)

Quote:

And how am I supposed to know that thats actually Standard C++? Does MS even support Standard C++?

Microsoft C++ compiler version 8.0 is 98.9% compliant with the latest C++ standard (from what I remember). They only left out the template export functionality, I think.

But why are you supposing that Microsoft's C++ has proprietary extensions not explicitely mentioned? if you find something like that, please notify Microsoft...because for all their proprietary extensions, they have a "Microsoft specific" region in their help.

Quote:

Not to mention that the page is virtually unreadable. I suspect they expect me to be using IE, which is certainly NOT the case.

Boy, you are a whiner, aren't you? I am using Firefox and the page looks ok.

Zaphos said:

I don't have much to say about the specifics of the argument; I'm not entirely sold on it but I lack both expertise & interest. Interest, because really, as someone who is not a language developer but rather a language user, I find it hard to ignore the context in which the language is presented. The tools and features surrounding a language do matter. Shawn said something interesting in a similar thread, pointing out that even the language 'culture' affects the experience of using the language. As an end user, the quality of the language experience is not determined by just the core specification, but by all sorts of external factors surrounding the language.
It's only in a very abstract context, or from the perspective of someone looking to design new languages, that it seems worthwhile to look at the core of the language alone. And even the language designer needs to look beyond that quite soon after specifying the language -- no one needs a language that's only good in theory.

Exactly! you said it very nicely and I couldn't agree more with you. That's why I would like to see things in C++ fixed because if they do so, C++ will be the superior language. The right ingredients are there, but the soup needs fixing.

Marcello
Quote:

Exactly! you said it very nicely and I couldn't agree more with you. That's why I would like to see things in C++ fixed because if they do so, C++ will be the superior language. The right ingredients are there, but the soup needs fixing.

So until they do, I'll use better languages. =P

I would consider it blind faith to consider C++ the 'ultimate' language.

Marcello

Goalie Ca
Quote:

I would consider it blind faith to consider C++ the 'ultimate' language.

No... because we all know that french is the ultimate language.

Thread #585895. Printed from Allegro.cc