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

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.

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

axilmar
Member #1,204
April 2001

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

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.

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

axilmar
Member #1,204
April 2001

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++
Member #1,816
January 2002

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
Member #794
November 2000
avatar

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

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.

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

Carrus85
Member #2,633
August 2002
avatar

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

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++
Member #1,816
January 2002

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

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

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++
Member #1,816
January 2002

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

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++.

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

Steve++
Member #1,816
January 2002

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

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
Member #7,398
June 2006
avatar

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...

-----------------------------
Anatidaephobia: The fear that somehow, somewhere, a duck is watching you

Marcello
Member #1,860
January 2002
avatar

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++
Member #1,816
January 2002

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
The Progenitor
April 2000
avatar

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

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 Progenitor
April 2000
avatar

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++
Member #1,816
January 2002

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
The Progenitor
April 2000
avatar

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
Member #1,468
August 2001

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 ...)



Go to: