different try-finally approach

L

Lew

Pitch said:
Pitch said:
public void doSomething()
// throws [MyResource|App]Exception
{
final MyResource res; [snip]
try
{
// do something with res
}
finally
{
res.close()
}
}
This implies res is not going to get null in the last try-block. I think
this is a real possibility if more programmers work on the code so you'd
still need if != null
No, 'res' is guaranteed not to be null.
What about this:

assert res != null;

try
{
// do something with res
res = null;
}
finally
{
res.close()
}
Error: cannot assign a value to final variable res
1 error

The helpful compiler can now enforce the rules; no need to waste expensive
run-time tests or exceptions. With a dash of immutability, fine-grained
exception handling to distinguish acquisition failure from in-stream failure,
carefully positioned 'assert' invariants, and a properly-scoped 'finally' to
enforce resource release, one provably locks out the Bad Things from run-time
possibility.

It's worth a little extra care in the lower levels of resource client code to
gain such robustness.
 
D

Daniel Pitts

Pitch said:
In java it is common to check if the resource is null in finally
statement, before closing it:

public void doSomething() throws MyResourceException
{
MyResource res = null;
try
{
res = new MyResource();
// do something
}
finally
{
if (res != null) res.close()
}
}


But in some other languages this is the preferred way:

public void doSomething() throws MyResourceException
{
MyResource res = new MyResource();
try
{
// do something
}
finally
{
res.close()
}
}


The first example ensures nothing more than the second one, right? If
the constructor throws an exception the "res" is null, so it can't be
closed anyways.

So, my question is - why the extra coding in java? Am I missing
something?

MyResource res1 = new MyResource("a");
MyResource res2 = new MyResource("b"); // throws exception
oops, res2 is null, but res1 is not.


This is why I miss RAII from C++.
 
D

Daniel Pitts

Bill said:
In actual practice I tend to have a utility method like this somewhere
in a project that uses lots of I/O:

public static void close (Closeable c) {
if (c != null) {
try {
c.close();
} catch (IOException e) {
// Ignore.
}
}
}

which gets rid of the (IMHO useless) close() exceptions, and also allows
nulls (which it ignores).

Then it's

finally {
IOUtils.close(foo);
IOUtils.close(bar);
IOUtils.close(baz);
}

or similarly.

As for the objection that more than one job is being done, maybe, maybe
not. In many cases a single conceptual job involves more than one
stream. For example, copying something out of one file into another
involves working simultaneously with an InputStream and an OutputStream.
These might be wrapped in Reader and Writer, or records from a single
input file might be signal-splittered to several distinct output files,
one for records of type X, one for records of type Y, etc., so there'd
be one InputStream and multiple OutputStreams. Or several input files
are appended -- one of each stream type again, but with the InputStream
being reassigned periodically.
I've written another one.

The gist of it (pseudo-code)

interface Opennable<T extends Closable> {
T open() throws Exception;
}

public class Resource<T extends Closable> implements Closable{
private final Opennable<T> openable;
private T closable;
public Resource(Opennable<T> openable) { this.openable = openable; }
public void open() throws Exception { closable = openable.open(); }
public T get() {
return closable;
}
public void close() throws IOException {
if (closable != null)
closable.close();
}
}

public class ResourceUtils {
public static <T> T runThenClose(Callable<T> callable,
Resources<?>...resources) throws Exception {
boolean normalReturn = false;
try {
return callable.call();
} finally {
for (Resource<?> resource: resources) {
try {
resource.close();
} finally ( {
continue;
}
}
}
}
}
 
L

Lew

Daniel said:
MyResource res1 = new MyResource("a");
MyResource res2 = new MyResource("b"); // throws exception
oops, res2 is null, but res1 is not.


This is why I miss RAII from C++.

Yeah, there's a fair amount of boilerplate in opening multiple interdependent
resources that you have to grind out yourself in Java.

You can get pretty close to RAII in Java, though you might need to very
gingerly spike a finalizer into the mix. You just have to plod through the
source lines that entails.

IDEs today sport macro facilities that let you insert such boilerplate into
your source with a few keystrokes. E.g.,

{
final Resource r1;
final Resource r2;

try
{
r1 = Resource.getInstance();
r1.open();
}
catch ( ResourceException re )
{
logger.error( "Unable to open r1", re );
return;
}
try
{
r2 = Resource.getInstance();
r2.open();
}
catch ( ResourceException re )
{
logger.error( "Unable to open r2", re );
close( r1 );
return;
}
assert r1 != null && r2 != null;
assert r1.isOpen() && r2.isOpen();

try
{
// TODO:
}
finally
{
close( r1 );
close( r2 );
}
}
 
B

Bill McCleary

Lew said:
Yeah, there's a fair amount of boilerplate in opening multiple
interdependent resources that you have to grind out yourself in Java.

You can get pretty close to RAII in Java, though you might need to very
gingerly spike a finalizer into the mix. You just have to plod through
the source lines that entails.

IDEs today sport macro facilities that let you insert such boilerplate
into your source with a few keystrokes.

Clojure today sports macro facilities that let you avoid such
boilerplate in your source entirely -- it's generated for you at run
time. (Clojure is a Lisp that runs on the JVM and can easily operate on
Java objects and call Java methods. Downside, arguably: no static type
checking or checked exceptions having to be handled or declared. On the
plus side for many of you, almost every variable is implicitly final. A
functional style of programming is strongly encouraged, though stateful
loops, mutable references, and mutable Java objects can all be used --
including java.io's streams. Clojure comes with a with-open macro that
wraps Closeable assignments and a body of code in a try ... finally that
ensures they get closed, not unlike the C# resource-usage control
construct. But the macro facility means you can create your own control
constructs to suit your needs. One like with-open to dispose() frames
and ImageReaders, say, or that wraps code and logs and rethrows all
exceptions, or that expands into a class definition with several fields
and appropriate equals, toString, hashCode, and compareTo methods with
the last using the fields in a specified order. Whatever floats your boat.)
 
P

Pitch

MyResource res1 = new MyResource("a");
MyResource res2 = new MyResource("b"); // throws exception
oops, res2 is null, but res1 is not.

This example does not apply because I would wrap the second constructor
in another try-finally.

MyResource res1 = new MyResource("a");
try
{
MyResource res2 = new MyResource("b"); // throws exception
....
 
P

Pitch

I learned a new term today: ?Bulldozer code?.

It is one of the ?Symptoms of inability to reason
about code? and is being described as code

?that gives the appearance of refactoring by breaking
out chunks into subroutines, but that are impossible
to reuse in another context?

http://sites.google.com/site/yacoset/Home/signs-that-you-re-a-bad-programmer

I see, but as I said, readability is more important than anything, even
than the code is actually working.

However, I see you have a talent in finding smart-ass programmer's on-
line advices. But remembers this, the guy who wrote this is just a guy
and even if it is on Google's site it doesn't mean its all true.
 
L

Lew

Pitch said:
I see, but as I said, readability is more important than anything, even
than the code is actually working.

So you would publish or accept non-functional but eminently readable code?

I find that notion difficult to endorse.
However, I see you have a talent in finding smart-ass programmer's on-
line advices. But remembers this, the guy who wrote this is just a guy
and even if it is on Google's site it doesn't mean its all true.

Nor that it's false.
 
P

Pitch

So you would publish or accept non-functional but eminently readable code?


Of course not. That's why we have several phases of testing.

In the development process, many programmers tend to just make things
done, mostly because of the deadlines, or because they thing tha task is
dull or whatever.

The right way is to produce a readable, hence quilckly understandable
code. If you focus your self on that, the program flow will be much more
claer/logical and hopefully without conceptual errors.

I've worked with many inexperienced prorgammers. They like to produce
big methods, with several sections, with too many if-statements. The
first thing I do is to break it to this, as Stephan said, "Bulldozer
code", so I (and others) can easily get a hold of it. Only then it's
time to make significant changes.

I just remembered a SaxParser handler with more than 10 pages of code.
Would you say that's ok?
 
A

Arved Sandstrom

Pitch said:
Of course not. That's why we have several phases of testing.

In the development process, many programmers tend to just make things
done, mostly because of the deadlines, or because they thing tha task is
dull or whatever.

The right way is to produce a readable, hence quilckly understandable
code. If you focus your self on that, the program flow will be much more
claer/logical and hopefully without conceptual errors.

I've worked with many inexperienced prorgammers. They like to produce
big methods, with several sections, with too many if-statements. The
first thing I do is to break it to this, as Stephan said, "Bulldozer
code", so I (and others) can easily get a hold of it. Only then it's
time to make significant changes.

I just remembered a SaxParser handler with more than 10 pages of code.
Would you say that's ok?

I thought that the website cited by Stefan was pretty decent, but recall
that the programmer who wrote that page described the various bullets as
"symptoms". Some of the symptoms are just flat-out bad, but others are
maybe a problem, maybe not, depending on context.

I've done "bulldozer" refactoring myself for exactly the reasons you
mention. I don't find that code folding in IDEs quite does the trick, so
to understand the overall logic in a giant method with lots of
conditionals I'll also extract the various "if" and "else" blocks out
into private methods. I take this particular symptom with a grain of
salt - sure there's lots of little "subroutines", but all they are are
private helper methods, in the same class, and who cares who much
reusability and cohesion they have?

I should add, it's not so much huge switches or huge if-else if-else
if-...else if-else statements that I have problems with, it's lots of
"if" nesting. Even commenting the ends of blocks doesn't always help so
much.

It goes without saying that the code should be readable, but it
shouldn't be free of conceptual errors _because_ you are striving for
conceptual errors. Because you are coding to a detailed design, are you
not? :)

AHS
 
P

Pitch

It goes without saying that the code should be readable, but it
shouldn't be free of conceptual errors _because_ you are striving for
conceptual errors. Because you are coding to a detailed design, are you
not? :)

Well, I'm not actually, at least not to the extent I would want to. :(
 
V

Volker Borchert

Mike said:
That's my feeling too, but at some point, someone anal is going to
profile it and ask where all those empty ArrayLists came from :)

Make it (uncompiled, untested)

public final class LinkedListEntry<T>
{
private final T v;
private final LinkedListEntry<T> n;

public LinkedListEntry(final T value, final LinkedListEntry<T> next)
{
v = value;
n = next;
}

public T value()
{
return v;
}

public LinkedListEntry<T> next()
{
return n;
}
}

public static void close(final Closeable... closeables) throws IOException
{
LinkedListEntry<IOException> exceptions = null;
for (final Closeable cl : closeables)
{
try
{
cl.close()
}
catch (final IOException ex)
{
exceptions = new LinkedListEntry<IOException>(ex, exceptions);
}
}
if (exceptions != null)
{
throw new WrappedIOException(exceptions);
}
}

Given that exceptions are intended to be thrown rarely, in exceptional
circumstances, the work for the WrappedIOException ctor to reverse the
order and the overhead of an object per exception should be affordable.
And the LinkedListEntry might come in useful at other places anyway.
Or one could (ab-use) AbstractMap.SimpleImmutableEntry.
 
D

Daniel Pitts

Stefan said:
I learned a new term today: »Bulldozer code«.

It is one of the »Symptoms of inability to reason
about code« and is being described as code

»that gives the appearance of refactoring by breaking
out chunks into subroutines, but that are impossible
to reuse in another context«

http://sites.google.com/site/yacoset/Home/signs-that-you-re-a-bad-programmer

I think the definition of that term is dangerous. Sometimes I break out
subroutines not for reuse, but for readability. If you can describe in
English what a section of your method code does, then writing a method
with a descriptive name may improve readability.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,596
Members
45,131
Latest member
IsiahLiebe
Top