

Exception Safety, Garbage Collection etc. (a.k.a. Why Does Java Suck So Bad?) - eplawless
http://www.slideshare.net/eplawless/exception-safety-and-garbage-collection-and-some-other-stuff
It’s very likely that you’ve been writing totally incorrect code without realizing it. Once you do realize it, it’s usually not too hard to fix the problem, depending on the language you're using.
======
grimlck
Interesting how java is the only language included in the title, but the
slides have the opinion that C#, Ruby and Python all suck as well.

Seems like a cheap way to get upvotes.

~~~
rst
And there actually is an idiomatic way to avoid the problem in Ruby:

    
    
       File.open("...") do |f|
         firstline = f.readline
         ... stuff that might throw an exception ...
       end
    

If the "stuff" throws an exception, the file gets closed automatically. And
while File is a library class, it's getting no special favors here --- any
pure ruby library can easily implement similar APIs, and ActiveRecord's
connection pool, for example, actually does.

~~~
mullr
Which counts as the sugar which he mentions. See also "using" in C#. These are
pretty clearly design warts. WPF (C# UI library) jumps through some
interesting hoops to make it look like all your resources can be properly
garbage collected, but even then it tends to come back and bite you for any
non-trivial application.

~~~
bonzoesc
It doesn't really taste like syntactic sugar though; it's a special
functionality of the standard library, and you could easily get away without
knowing about the Java/C-style API of keeping a file handle that has to be
controlled around.

~~~
CodeMage
Out of the three languages he mentions as having syntactic sugar, he was wrong
only in Ruby's case. Like you said, it's not a specific syntactic sugar for
Dispose pattern, unlike C#'s "using" and Python's "with".

~~~
JoachimSchipper
Honest question: what's the difference between Ruby and Python/C# here?

~~~
CodeMage
Let's look at rst's example:

    
    
       File.open("...") do |f|
         ... stuff that might throw an exception ...
       end
    

The syntax you see here is for passing a block to a method. In this case,
you're passing a block to File.open, which opens the file, executes your block
with it and then makes sure to close the file no matter what.

In Python, you would do:

    
    
       with open("x.txt") as f:
         ... stuff that might throw an exception ...
    

What this does is evaluate open("x.txt"), call the __enter__ method on the
resulting value (called the context guard), assign the result of the __enter__
method to f, executes the body of the with statement and makes sure to call
__exit__ method of the guard.

The difference is that the syntax used in the Ruby example uses is not
syntactic sugar for Dispose pattern, it's part of Ruby's syntax for working
with blocks in general, whereas the syntax used in Python example is syntactic
sugar meant for Dispose pattern (but can be used for other stuff too).

------
yonilevy
The majority of the comments seem to be negative, yet many of them reflect a
misunderstanding of RAII. I've argued the exact argument the author does many
times before and got similar responses, it seems to be hard to convey the
power of RAII to people who haven't practiced it before. The meaning of RAII
is that you can tie a resource to the lifetime of an object, in an environment
where the object gets destroyed deterministically. There are two practical
uses: 1) You can hide the fact an object is holding a resource from users of
the object. 2) You can leverage the power of objects within the language and
apply it to resources. The part regarding languages allowing something that
might look similar with syntactic sugar didn't convey it's message very well.
The syntactic sugar other languages are introducing is great on its own, but
it's inferior to the object based approach since it doesn't allow (1) nor (2).
It's annoying that languages with garbage collection support have gained a lot
of attention solely due to the fact that you don't have to worry about freeing
memory, while languages with RAII support in which you basically don't have to
_worry_ about freeing any resource, got none.

~~~
mattgreenrocks
Amen.

RAII will be in the next great language, as it is a useful tool. This is not
an academic concern, it is something that happens all the time due to rushed
deadlines, stressed developers, or simple naivete.

People love to slag off C++ but the higher-level devs have done some serious
thinking about how to engineer robust programs. Sutter's 'Exceptional C++' is
eye-opening the first time around, and the concepts are applicable to any
language that has exception handling. Programming in a transactional manner
has visibly improved my designs -- mostly through the paranoia that almost any
statement could throw an exception.

------
orangecat
Python's "with" statement handles this scenario:
<http://effbot.org/zone/python-with-statement.htm>

~~~
munificent
The author is aware of that, but you have to remember to use "with". If you
forget to use it, you can still have unclaimed resources.

~~~
rapala
You also need to remember to use RAII, and that always requires creating a
class. You also need to get RAII right, where as Python's with is implemented
for you.

Also there's no mention about the fact that Java forces you to check for
exceptions (well not for unchecked ones, but those should not be fatal, and I
never really got their idea). You can't forget the try-catch.

~~~
shasta
The library author needs to remember to use RAII, but the client doesn't need
to remember anything (as in his examples). Whereas with 'with' it's the
opposite - the client has to remember to use it.

------
revetkn
...am I reading correctly that his argument for using C++/D (!) is that it's
hard to remember to say this:

    
    
        try {
          mightFail();
        } finally {
          doCleanup();
        }
    

instead of this:

    
    
        mightFail();
        doCleanup();

~~~
abstractfactory
The second example should actually be

    
    
        class C {
          void mightFail() { ... }
          ~C() { doCleanup(); }
        };
    
        C c;
        c.mightFail();
    

Anyway, I hate this slide deck so much.

1\. The author's point could be made in far fewer slides. As in, like, two
slides. I hate presentations that are disrespectful of the audience's time for
the sake of being cute.

2\. I am generally unimpressed by arguments of the form: (a) Language X has
flaw Y. (b) Therefore language X is unsuitable for development. This can be
instantiated for every language X for some flaw Y and is not an argument
against any language. You need to additionally make the argument: (c) Y is so
serious that it outweighs the considerations in favor of X and against the
other languages one might reasonably use. Of course (c) is an incredibly high
bar, which is why most anti-language zealot arguments do not even attempt to
make it, and also why most anti-language zealotry is silly.

In order to do (c) in this case, you would have to make the case that writing
finally clauses is worse overall than, e.g. debugging memory corruption
errors, and writing copy constructors and overloaded assignment operators, and
all the other baggage of C++, rather than handwaving them away with "the
downsides have been exaggerated" _.

_ Which, by the way, is ironically the biggest flaw of this slide deck: the
author vastly exaggerates the downsides of finally. try/finally is no worse
than checking the result codes of C syscalls, and it is sometimes better. I
don't recall the C style of programming stopping Ken Thompson from building
great things and I doubt that try/finally is actually what stops Java
programmers from building great things.

~~~
krypes
You seem to have failed to grasp that the slides are arguing for RAII. While
admittedly mildly trollish, it disparages java along with C#/ruby/python
implicitly in favour of C++ only because C++ has the most 'correct'
implementation of RAII.

There is no argument against try/catch/finally, the argument is that the most
common usage of try blocks is for dealing with resource management, not actual
exceptions in program state. Given exceptions should be used to expression
'exceptional' program states, that is a significant downside to code
readability.

Syntactic sugar like using/yield/with blocks improve the signal to noise ratio
of try block usage but still rely on programmer acceptance of that idiom.
Ideally, the responsibility of cleanup would be moved entirely to the class
implementation rather than the consumer. C++ did this with destructors. In a
managed world where maybe you don't always want an eager dispose, rather than
syntactic sugar in the caller, move it to the signature of the dispose.
Something along the lines of

public scoped void Dispose() { .... }

Alternatively, @Scoped or <Scoped> if you don't want more keywords. The topic
is partly to blame but RAII is orthogonal to whether a language is garbage
collected or not. It's sad that in an age where PLs are undergoing a sort of
renaissance period, mention of C++ causes everyone to circle their respective
wagons.

~~~
aidenn0
And RAII in C++ relies on programmer acceptance of that idiom.

~~~
fauigerzigerk
Arguably it relies on the acceptance of fewer programmers, the library
writers.

------
latch
_if PHP gets something right before your language does, you should reassess
your life goals_

:)

------
aboodman
I am not super familiar with all the details of Java inner classes, but why
can't you get most of the way there by doing something like:

    
    
      DB.open(new Runnable() {
        public void run() {
          // ... do stuff here ...
        }
      });
    

You can even design your resource layers such that they can only be used this
way (or are easiest to use this way).

Basically, I'm just stealing the JavaScript-y way of doing this that uses
closures:

    
    
      DB.open(function() {
        ...
      });

~~~
aboodman
Answer: the inner class can only access constant locals :(. So you have to put
any mutable state in members.

Blech. This might work for some cases, but would be a huge pain in the ass in
others.

------
JulianMorrison
Also, Go gets this right with "defer", and with mostly deterministic error
handling (panicking is not the normal way to signal an error, returning a
status is).

~~~
munificent
That just pushes the problem around. You don't have to worry about forgetting
to catch an exception, you have to worry about ignoring an error code.

~~~
JulianMorrison
Go's multiple return at least makes that simpler than C, you don't have to
remember to check a global error code, and there are no magic return codes
multiplexed with the expected response.

But the fundamental difference is that if you have code that does

    
    
        a()
        b()
        c()
    

then you can guarantee that a() will be executed, then b(), then c(). And if
there are any branches in case of errors, they will be explicit. Exceptions
surround every statement with the possibility of an unannounced exit.

------
tmsh
High-performant, world-class C++ is fairly well understood (afaik) to only use
a very limited subset of C++'s features (e.g., see the JSF Coding Standard or
Google Style Guide or go work for a hedge fund where low latency and high
reliability is important).

The same for Java. I honor all the exceptions in the standard/platform
libraries. But I see past the hype for my own interfaces. Imho, 9/10 exception
classes clutter the interface. 9/10 (again for high reliability, high quality
code that you want to work reliably but also be flexible enough to extend),
what you want to return is a boolean (and log) for stateful methods. Meanwhile
prefer stateless methods wherever possible. And generally speaking treating
the JVM and Java as basically a really really high performant scripting engine
(i.e., closer to JS than C; though the syntax is somewhere in between). Imho,
if you can't do RAII, and you're not deterministic, you are basically a
scripting language (or are in the GC family of languages, if you don't like
the term 'scripting' -- I think it's cool...).

Anyway, that's how I approach it. But I don't buy into the hype of exceptions
most of the time (though of course I honor whatever contract other libraries
use).

~~~
dkersten
_Imho, 9/10 exception classes clutter the interface._

Thats why checked exceptions are such a bad idea... Personally, I really like
Go's defer, panic, recover mechanism[1] for handling exceptional
circumstances.

[1] <http://blog.golang.org/2010/08/defer-panic-and-recover.html>

------
kstenerud
What you really want is something along the lines of:

    
    
        void myMethod()
        {
            disposable File myFile = new File(somePath);
    
            // ... do stuff with the file
    
            // "disposable" modifier causes myFile to be
            // forcibly destroyed upon leaving scope for any
            // reason (except if the disposable object itself
            // is returned from the method).
        }
    

An idiom designed specifically for the purpose of resource management would
make for a far cleaner implementation than shoehorning an existing mechanism.

You'd probably also need to add checking for references to the object by
still-living objects (i.e. objects not eligible for gc). If any live object
has a reference to the disposable object, its "disposable" status gets
removed. Similarly, returning the disposable object from the method also
strips its "disposable" status. It would add extra processing at the end of
the scope level, but generally methods that create/use resources don't need to
be lightning fast anyway.

You could even add the "disposable" modifier to class definitions, making all
instances of that class disposable by default (and thus destroyed unless
referenced or returned).

~~~
aliguori
It's not so easy because what happens if you have code like this:

    
    
      static File globalFile;
      
      void register_file(File aFile)
      {
          globalFile = aFile;
      }
      
      void myMethod()
      {
          disposable File myFile = new File(somePath);
      
          register_file(myFile);
      }
    

If you answer, "add referencing counting", reference counting isn't perfect
because you can create cyclic references.

The only reason RAII works in C++ is because you can refer to an object by
value and separately by reference. You can create stack-based objects that
have a defined scope.

You really can't have this in a language that always treats objects only by
reference.

~~~
kstenerud
My answer would be to create a shortcut in the existing reference system of
the gc. Invoke a subset of the gc which checks a reduced list of object
references made from that scope or deeper.

Reference counted systems only work if you don't create cyclic (strong)
references, so that argument is moot. In fact, reference counted systems can
deal with resource objects easily so long as the compiler/interpreter ensures
that pending autoreleases are executed when unwinding the stack during an
exception.

------
JulianMorrison
I think you can avoid nesting finally thus:

    
    
        X x = null;
        Y y = null;
        try{
          x = foo();
          y = bar();
          yadda(x,y);
        } finally {
          if (x!=null) x.dispose();
          if (y!=null) y.dispose();
        }

~~~
latch
what happens if x.dispose() throws an exception?

if (x != null) try { x.dipose(); } catch (Exception){} }

it's why the using keyword is so nice. Still, this is all hoops languages
force us to deal with when they shouldn't (which is the OPs point)

~~~
JulianMorrison
You're lucky Java is checked at compile time. Ruby would eat that "no such
method dipose" and silently leak x.

~~~
CodeMage
_You're lucky Java is checked at compile time._

Not lucky enough, because x.dispose() could throw an unchecked exception.

------
jriddycuz
The problem with this whole argument is that the author assumes that
deterministic memory performance is completely necessary. It's certainly nice,
but there are so many times when it just doesn't matter.

While I agree that Java sucks because it makes certain very common things
require extreme verbosity, worrying about garbage collection isn't all that
important except in systems-level programming (which isn't done in Java
really), and large GUI that need tons of memory and still need responsiveness.
But many people wouldn't even think to use Java in those cases anyways, so I'm
not really sure what this guy's point is.

~~~
chris_j
Read the slides again. The author isn't concerned about deterministic memory
performance. He's concerned about the fact that that you can't do RAII in Java
and therefore any method that allocates resources, performs an action that
could throw an exception and then deallocates the resources must wrap the
action in a try...finally block. This is overly verbose and the compiler won't
tell you if you forget to do it.

------
wwrap
Non-slideshare link:

[http://docs.google.com/viewer?url=https%3A%2F%2Fs3.amazonaws...](http://docs.google.com/viewer?url=https%3A%2F%2Fs3.amazonaws.com%2Fppt-
download%2Fraii-110506011720-phpapp01.pptx%3Fresponse-content-
disposition%3Dattachment%26Signature%3D5lrdrqUoc6rD0E2fjI06%2FOHz4%2Fs%3D%26Expires%3D1304722818%26AWSAccessKeyId%3DAKIAJLJT267DEGKZDHEQ)

Edit: Warning. Actually seems to cut off some of the slides.

------
keytweetlouie
This fact has lead to the popularity of the springframework in Java. They use
the template design pattern to hide all of the resource acquisition and
release. This makes it much easier to code as you don't have to "remember" to
close your db connections. The remember argument is somewhat weak because you
still need to remember to write your destructor. I do buy that it's easier to
remember it in one place than all over the code.

------
kleiba
In the Java example with three try/finally's, he calls 'dispose()' on a File.
I've never seen this before, what does it do? Or did he just hallucinate that
to make the example look more dramatic?

