Christopher Smith wrote:
The fact that you said "C/C++" kind of screams that you aren't getting
the point here. C most definitely does not have destructors, and in fact
most resource management related bugs in C++ can be traced back to
failing to apply C++'s semantics for avoiding these problems. One of
C++'s greatest strengths (C compatibility) really turns out to be a
short coming in this regard: programmers code C++ programs like they are
C programs.
Sorry. I misspoke. I tend to think of manual resource management and
lump C/C++ together.
You are correct that C++ has destructors. And this works fantastically
well as long as programmers only use the STL and access memory.
Once you touch non-memory resources or have to write your own
destructors, it breaks down.
You can't put cleanup code for things like sockets into destructors
since even closing a socket can cause errors. And destructors can't
throw exceptions. Whoops. Hence, back to manual resource management
and C++ is no better than Java (it is, in fact, worse but I'll just
assume equality).
And, if someone has to write their own destructors, there are a bunch of
guidelines that they have to know cold so as not to get things wrong. Pass.
Garbage collection doesn't manage sockets at all. That's the problem.
And neither can destructors. Sorry. If you don't understand that,
you're in deep trouble already. Please go read "Exceptional C++" by
Herb Sutter (Gah! Checking amazon.com he's up to 3 *entire* books on
the problems of exceptions. Yuk. Glad I don't do C++ anymore ...)
Destructors only *look* like they can clean up non-memory resources.
And that's the real problem with C++ ... so many things *look* like they
can solve your problem.
It's only after writing 10,000 lines of code that the subtleties start
to bite. By then nobody wants to go back and redo the architecture to
get it right. Been there, done that, got the scars, don't want any more.
There are certainly classes of programs where this stuff doesn't matter,
particularly with building a simple prototype. If you are trying to
claim that this isn't an issue for a lot of Java programs, check out how
man serious projects don't have a "finally" clause in them. ;-)
Java does use finalizers as a safety net for sockets:
"On the other hand, nonmemory resources like file handles and socket
handles must be explicitly released by the program, using methods with
names like close(), destroy(), shutdown(), or release(). Some classes,
such as the file handle stream implementations in the platform class
library, provide finalizers as a "safety net" so that if the program
forgets to release the resource, the finalizer can still do the job when
the garbage collector determines that the program is finished with it.
But even though file handles provide finalizers to clean up after you if
you forget, it is still better to close them explicitly when you are
done with them. Doing so closes them much earlier than they otherwise
would be, reducing the chance of resource exhaustion."
And, BTW, "finally" gets used for locking in Java, as well.
I have the same opinion about the Collections interface in Java. I use
the concrete interface rather than the Collection interface. Use the
richest interface that makes sense.
"concrete interface"?
I use will use LinkedList (the actual data structure) instead of Queue
(the collections interface).
Java prefers Queue on the theory that you can change the underlying
implementation (LinkedList). I'm with Scott Meyers (see Effective STL)
that this is a red herring. You normally need guarantees about
performance and complexity (big O() notation) that preclude changing the
underlying data structure anyway.
I do find the fact that I can't create a default action for interfaces
in Java to be annoying.
If you use factories and dynamic proxies you can build a framework that
will do it for you. You can probably do something similar with
attributes as well.
"The usage of design patterns indicates a language failure."
I forget where I heard it, but I am now convinced of this. If I have to
use patterns, I am in the wrong language.
This is a totally different point, but the difference is that in C++ you
can allocate objects and arrays on the stack, which really makes a huge
difference (so much so that the next Java runtime is going to have
escape analysis so that it can finally allocate on the stack... and the
performance win from this is huge).
While that's useful, allocating from the heap is almost as cheap as the
stack in Java. What memory pools lose in call efficiency they gain in
cache/memory locality.
The primary wins for escape analysis are:
1) alleviating runtime checks (big one)
2) eliding synchronization barriers (this is the major expense in Java
allocation from the heap--occasionally you have to synchronize your heap
with other threads)
3) tail recursion (this is *huge* for other languages on the JVM)
Overall execution time only drops between 2-23% with a median of 7%.
Nothing to sneeze at, but certainly not "huge".
(See: http://citeseer.ist.psu.edu/choi99escape.html)
-a
--
[email protected]
http://www.kernel-panic.org/cgi-bin/mailman/listinfo/kplug-lpsg