small java exercise

S

Stefan Ram

Patricia Shanahan said:
My question is specific to Java, so I could wrap the multi-exit
code in a try-finally and do the call in the finally block.

By this finally-block you re-introduce a single exit point:
This single exit point of the wrapped code now is the end of
the finally block. So this wrapped code does not count as
multi-exit code, it is single-exit code again.
This is especially the case for recursive methods.
int factorial(int n){
int fact;
if(n < 0){
throw something;
}
if(n == 0){
fact = 1;
}else{
fact = n * factorial(n-1);
}
return fact;
}

Just for the records, I might write this as:

int factorial_( final int n ){ return n == 0 ? 1 : n * factorial_( n - 1 ); }
int factorial( final int n ){ if( n < 0 )throw ...; return factorial_( n ); }
 
P

Patricia Shanahan

Stefan said:
By this finally-block you re-introduce a single exit point:
This single exit point of the wrapped code now is the end of
the finally block. So this wrapped code does not count as
multi-exit code, it is single-exit code again.

Looking at it that way, I would argue that try-finally makes the
multi-exit to single-exit refactoring trivial.

Many of the familiar arguments for single-exit amount to preemptive
avoidance of ever having to do that refactoring. Without try-finally, it
really is something that should be avoided if possible.

Patricia
 
M

Martin Gregorie

Patricia said:
I thought single exit was a very good idea when I was programming in
assembly languages and later in C. Is it a good idea in Java, or just a
habit?
Good question. As you say, it is a very good strategy in C and
assembler. It mostly works for me in Java though, as I said earlier, its
mainly conditioned by my tracing philosophy. I much prefer using trace
statements to a debugger and always leave tracing in production code.

I frequently start off writing a class with multi-exit methods for the
same reasons that you give but often switch and rewrite them as single
exit after a few methods have been written and it becomes obvious that
an exit tracing capability would be useful. Exit tracing is a real pain
for multi-exit methods and does a good job of obscuring the logic. I
realize this is probably the mark of insufficient preliminary thought
but at least I typically make the switch early in the process of coding
the class, so relatively little code needs to be restructured.

I prefer to trace the exit from a method rather than entry to it. This
allows a trace file to contain one line per method called while still
showing the method name, arguments and return value. Of course, if the
method is large and complex then increasing the trace detail level
should trace its entry and (possibly) still higher detail levels would
trace the internals. The latter tends to comes out in the wash if things
are organized so the trace detail level approximates the method call
depth in the program.
 
L

Lew

Martin said:
Good question. As you say, it is a very good strategy in C and
assembler. It mostly works for me in Java though, as I said earlier, its
mainly conditioned by my tracing philosophy. I much prefer using trace
statements to a debugger and always leave tracing in production code.

I trust you use a logging package in order not to create trouble for the
production code. I really hope you don't use System.out for your traces.

Otherwise, I would certainly ding such code in a review.
 
M

Martin Gregorie

Lew said:
I trust you use a logging package in order not to create trouble for the
production code. I really hope you don't use System.out for your traces.
So far all my Java code has been stand-alone executables and I have used
stderr for tracing. In this situation sending it to the system logger or
to a dedicated logging process is overkill: redirecting stderr to a file
is sufficient. However, all tracing is handled by a utility class, so
sending it elsewhere would involve a simple change to one method within
a dedicated class.
Otherwise, I would certainly ding such code in a review.
I'd agree with you if I was dealing with a multi-process system.

In a complex, multi-process system I might configure the system logger
to send my tracing info to a private log file. However, its more likely
that I'd use a custom logging process, partly for portability and partly
because that allows multiple copies of the system to keep their logging
output separate.

My current project offers yet another possibility. The main process will
be run as a cron task, so the best place to send error reports or
tracing is to stderr. Crond automatically collects all output from
stdout and stderr and e-mails it to the sysadmin. Problem solved. As a
bonus there's no additional code needed to analyze or rotate logs.
 
P

Patricia Shanahan

Martin said:
Good question. As you say, it is a very good strategy in C and
assembler. It mostly works for me in Java though, as I said earlier, its
mainly conditioned by my tracing philosophy. I much prefer using trace
statements to a debugger and always leave tracing in production code.

I frequently start off writing a class with multi-exit methods for the
same reasons that you give but often switch and rewrite them as single
exit after a few methods have been written and it becomes obvious that
an exit tracing capability would be useful. Exit tracing is a real pain
for multi-exit methods and does a good job of obscuring the logic. I
realize this is probably the mark of insufficient preliminary thought
but at least I typically make the switch early in the process of coding
the class, so relatively little code needs to be restructured.

I prefer to trace the exit from a method rather than entry to it. This
allows a trace file to contain one line per method called while still
showing the method name, arguments and return value. Of course, if the
method is large and complex then increasing the trace detail level
should trace its entry and (possibly) still higher detail levels would
trace the internals. The latter tends to comes out in the wash if things
are organized so the trace detail level approximates the method call
depth in the program.

Sounds like a very different approach to debug from mine. I tend to
collect information not just for a specific problem, but to answer a
specific question about the problem. It is possible that all exits from
some method would be the key information, but just as likely that I
would need to know about uses of a particular path inside the method.

I do sometimes want access to data from a normally running program,
without having a specific problem to debug. For example, one of my
programs uses a hill climbing heuristic that can reach a local optimum.
I often want to review its behavior. I supported that with logging calls
at points in the code where the information I need is most conveniently
available. I don't think any of them are method exits.

Patricia
 
T

tjmadden1128

try-finally does not require any use of exceptions. It just provides a
way of having the finally block run on completion of the try block.

I thought single exit was a very good idea when I was programming in
assembly languages and later in C. Is it a good idea in Java, or just a
habit?

Patricia

Habit, for me. In on C project I was working on long ago, the setjmp/
longjmp was wrapped in macros to resemble TRY/CATCH/FINALLY. So a
return in the middle of the macros would corrupt the return stack, and
the program would go to undefined places. At that point, it was a hard
and unbreakable rule. But I hate complex if/else if/else constructs
more, so if you are doing something like that just to maintain a
single exit point, I'd ding it.

I've never tried, but what would happen if a return was done inside a
try/finally block?

public class Foo {
private int pg=13;
private int r = 18;
public boolean Rating(int age) {
try {
if (age > r) {
return true;
}
}
finally { return false; }
}
}

Contrived example: not real code.
 
L

Lew

Martin said:
I'd agree with you if I was dealing with a multi-process system.

In a complex, multi-process system I might configure the system logger
to send my tracing info to a private log file. However, its more likely
that I'd use a custom logging process, partly for portability and partly
because that allows multiple copies of the system to keep their logging
output separate.

My current project offers yet another possibility. The main process will
be run as a cron task, so the best place to send error reports or
tracing is to stderr. Crond automatically collects all output from
stdout and stderr and e-mails it to the sysadmin. Problem solved. As a
bonus there's no additional code needed to analyze or rotate logs.

All of these are good ideas. Your analysis proves once again the triumph of
thought over dogma.

Both you and Patricia apply a variety tools to the situation, be it runtime
logging or tracing, profiling (as in Patricia's hill-climbing heuristics
example), or development-time debug statement-stepping with variable watches.
Neither seems to think that any one tool or technique is the be-all and
end-all of every related problem. Thoughtful analysis seems to inform the
choices.

Like the heuristic algorithm, programs represent local maxima of value to a
problem's solution. It is likely an untenable problem to prove that any given
program represents the absolute maximum value to a problem's solution.

I endorse the use of System.err for traces and the like. I do think logging
calls are of low enough coding overhead to justify their use even in fairly
small programs. Their main advantage there is the ability to turn them on and
off without rebuilding an app, allowing a maintainer to zero in on problems
only when they occur and virtually eliminate logging overhead otherwise.

But to insist that logging is the only solution would be to let dogma win over
thought.
 
L

Lew

I've never tried, but what would happen if a return was done inside a
try/finally block?

public class Foo {
private int pg=13;
private int r = 18;
public boolean Rating(int age) {
try {
if (age > r) {
return true;
}
}
finally { return false; }
}
}

Contrived example: not real code.

For this we turn to the JLS, ss. 14.20.2:
A try statement with a finally block is executed by first executing the try block. Then there is a choice:

* If execution of the try block completes normally, then the finally block is executed, and then there is a choice:
o If the finally block completes normally, then the try statement completes normally.
o If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S.

The finally return supersedes the try return.
 
L

Lew

I've never tried, but what would happen if a return was done inside a
try/finally block?

public class Foo {
private int pg=13;
private int r = 18;
public boolean Rating(int age) {
try {
if (age > r) {
return true;
}
}
finally { return false; }
}
}

Contrived example: not real code.

For this we turn to the JLS, ss. 14.20.2:
A try statement with a finally block is executed by first executing the try block. Then there is a choice:
...
* If execution of the try block completes abruptly for any other reason R, then the finally block is executed. Then there is a choice:
o If the finally block completes normally, then the try statement completes abruptly for reason R.
o If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and reason R is discarded).

The finally return supersedes the try return.
 
T

tjmadden1128

...
try-finally does not require any use of exceptions. It just provides a
way of having the finally block run on completion of the try block.

I thought single exit was a very good idea when I was programming in
assembly languages and later in C. Is it a good idea in Java, or just a
habit?

Patricia

For me, habit. I worked a long time on a C app with setjmp/longjmp put
in TRY/CATCH/FINALLY macro constructs. If a developer did a return
inside of the macros, the return stack was corrupted. I hate
convoluted if/else logic worse, though, so I am not completely against
multiple exit points. But something like this would not be good IMHO,
even though it works as I would expect:

public class EarlyExit {

private final int ageForPG = 13;
private final int ageForR = 18;

public boolean oldEnough(int age) {
try {
if (age > ageForR) {
System.out.println("Old enough");
return true;
}
}
finally {
if (age < ageForPG) {
System.out.println("Go away, kid, ya bother me!");
return false;
}
}
System.out.println("How old are you again?");
return false;
}

public static void main(String[] args) {
EarlyExit test = new EarlyExit();
test.oldEnough(16);
test.oldEnough(21);
test.oldEnough(10);
}

}

How old are you again?
Old enough
Go away, kid, ya bother me!

Tim
 
M

Martin Gregorie

Patricia said:
Sounds like a very different approach to debug from mine.
>
Maybe not that different. I suspect that an OO purist could easily throw
rocks at my class decomposition, but one result is that most of my
methods are fairly small and linear. If a method is becoming large and
complex it gets refactored into a set of private methods and the
hierarchic tracing levels adjusted so that higher debug levels will
cause the private methods to be traced. This way I don't get deluged
with low level tracing detail if I don't need to see it.
I tend to
collect information not just for a specific problem, but to answer a
specific question about the problem. It is possible that all exits from
some method would be the key information, but just as likely that I
would need to know about uses of a particular path inside the method.
The way that I use debugging levels more or less maps onto this.

Another neat idea that I first saw in the depths of George 3 is to
continually generate tracing, but put the result into a circular buffer.
If a fatal error occurs the buffer gets dumped in trace event sequence.
Its useful for solving problems in long running processes without
burying yourself in debugging output, but is only suitable for processes
that don't carry much context over from one logical piece of input to
the next.
I do sometimes want access to data from a normally running program,
without having a specific problem to debug. For example, one of my
programs uses a hill climbing heuristic that can reach a local optimum.
I often want to review its behavior. I supported that with logging calls
at points in the code where the information I need is most conveniently
available. I don't think any of them are method exits.
Yes, I do that too when needed. In addition, when performance and/or
memory use is critical I'll instrument the programs in the system so
that its easy to follow performance over time. Performance data might
get written to a database, if the system uses one, or to a log file.
Either way the system would almost certainly include a performance
analysis program.

A good (non-Java) example of this occurred a while back when I was away
from home and paying for my phone usage. I made sure ppp was logging
session stats and wrote a pair of gawk programs to extract ppp session
details from the log and consolidate them into a session diary so they
could be easily reconciled with the phone bill.
 
P

printdude1968

...
try-finally does not require any use of exceptions. It just provides a
way of having the finally block run on completion of the try block.
I thought single exit was a very good idea when I was programming in
assembly languages and later in C. Is it a good idea in Java, or just a
habit?

For me, habit. I worked a long time on a C app with setjmp/longjmp put
in TRY/CATCH/FINALLY macro constructs. If a developer did a return
inside of the macros, the return stack was corrupted. I hate
convoluted if/else logic worse, though, so I am not completely against
multiple exit points. But something like this would not be good IMHO,
even though it works as I would expect:

public class EarlyExit {

private final int ageForPG = 13;
private final int ageForR = 18;

public boolean oldEnough(int age) {
try {
if (age > ageForR) {
System.out.println("Old enough");
return true;
}
}
finally {
if (age < ageForPG) {
System.out.println("Go away, kid, ya bother me!");
return false;
}
}
System.out.println("How old are you again?");
return false;
}

public static void main(String[] args) {
EarlyExit test = new EarlyExit();
test.oldEnough(16);
test.oldEnough(21);
test.oldEnough(10);
}

}

How old are you again?
Old enough
Go away, kid, ya bother me!

Tim


I thought that the "try...finally" construct was used more for
handling exceptions. I've never seen it used as an alternate
to the if...else construct. Is this the intention of your code or am
I reading it wrong? Why are you using the try...finally
like that?
 
L

Lew

I thought that the "try...finally" construct was used more for
handling exceptions. I've never seen it used as an alternate
to the if...else construct. Is this the intention of your code or am
I reading it wrong? Why are you using the try...finally
like that?

tjmadden1128 was showing an example of what to avoid.

try ... finally is not only for exceptions. The catch block is not required
if there is a finally block.

A legitimate use of try ... finally is to guarantee to clean up resources such
as connections.

<snippet>
Connection cxn = getConnection();
if ( cxn == null )
{
throw new RuntimeException( "oops!" );
}
try
{
int result = doSomethingUseful( cxn );
if ( result == 0 )
{
return;
}
result = doSomethingElseUsful( cxn );
if ( result < 0 )
{
throw new RuntimeException( "drat!" );
}
return;
}
finally
{
close( cxn );
}
</snippet>
 
T

tjmadden1128

On May 17, 12:34 pm, "(e-mail address removed)" <[email protected]>
wrote:

I thought that the "try...finally" construct was used more for
handling exceptions. I've never seen it used as an alternate
to the if...else construct. Is this the intention of your code or am
I reading it wrong? Why are you using the try...finally
like that?

Just as a simple example, and I was curious as to how it would work.
Lew then pointed me to where the spec says what should happen.
Situations where I might use it is as Lew also posted, to ensure that
a database or socket connection or open file is closed. I would not
use it in place of an if/else construct, unless it really made code
clearer by replacing a bunch of nested if/else's. Even then, I'd think
long and hard on it.

Tim
 
C

Chris Smith

Patricia Shanahan said:
I thought single exit was a very good idea when I was programming in
assembly languages and later in C. Is it a good idea in Java, or just a
habit?

Among those who read my code, I'm somewhat famous for radically rooting
out and removing any repetition (or, as my detractors would say,
"consistency" :), so my answer is definitely biased by this. I find
that the single-exit-per-block rule prohibits certain abstractions that
I find useful. Once specific example is that when implementing equals
methods, I often find that the following pattern best expresses the
logic of the routine:

public boolean equals(Object o)
{
if (...) return false;
if (...) return false;
if (...) return false;

return true;
}

I can't find any way to write this that sticks to one exit point and
expresses the concept anywhere near as clearly, without writing an if
condition that's many lines long and blocks me from naming the results
of intermediate computations with local variables.

I would do this in other languages as well, though, even without the
try/finally construct. If I want something to happen when a function
completes, then I'd write:

someWrapper() { theRealFunction(); postprocess(); }
theRealFunction() { ... }

The only time I've really run into a major conflict about this is with
someone who wanted to add debug logging statements throughout the code.
I simply don't do that. I've learned to like AOP (despite still
believing it should be very rarely used in production) because it saves
me from having to do something that I find so utterly hideous as
sprinkling print statements throughout my code for debug logging.

So I'm definitely a little outside the mainstream, but that's my
perspective.
 

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

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top