Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » Which language is best?

This thread is locked; no one can reply to it. rss feed Print
Which language is best?
Goalie Ca
Member #2,579
July 2002
avatar

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

-------------
Bah weep granah weep nini bong!

Matthew Leverton
Supreme Loser
January 1999
avatar

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
Member #1,134
March 2001
avatar

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.

--
Software Development == Church Development
Step 1. Build it.
Step 2. Pray.

Goalie Ca
Member #2,579
July 2002
avatar

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.

-------------
Bah weep granah weep nini bong!

Matthew Leverton
Supreme Loser
January 1999
avatar

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
Member #2,579
July 2002
avatar

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.

-------------
Bah weep granah weep nini bong!

Karadoc ~~
Member #2,749
September 2002
avatar

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
Member #2,579
July 2002
avatar

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.

-------------
Bah weep granah weep nini bong!

Jonatan Hedborg
Member #4,886
July 2004
avatar

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
Member #2,606
August 2002
avatar

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
Member #3,935
October 2003
avatar

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
Member #4,886
July 2004
avatar

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
Second in Command
February 2005
avatar

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?

They all watch too much MSNBC... they get ideas.

Matthew Leverton
Supreme Loser
January 1999
avatar

You are comparing a kernel to the entire Windows platform?

ImLeftFooted
Member #3,935
October 2003
avatar

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
Member #2,815
October 2002
avatar

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.

--
"Do not meddle in the affairs of cats, for they are subtle and will pee on your computer." -- Bruce Graham

Shawn Hargreaves
The Progenitor
April 2000
avatar

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
Member #1,204
April 2001

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
Member #3,935
October 2003
avatar

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
Member #1,860
January 2002
avatar

D? :D

Marcello

Goalie Ca
Member #2,579
July 2002
avatar

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

-------------
Bah weep granah weep nini bong!

Marcello
Member #1,860
January 2002
avatar

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

Evert
Member #794
November 2000
avatar

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
Member #1,739
December 2001
avatar

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
Member #2,633
August 2002
avatar

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.



Go to: