A new means to return both a status code and a result to be used in a control statement is being described. [] (A Dual-Band If in Java, RAII in Java, resource handling in Java, instanceof, downcast, exception handing, structured control-flow), article, page 722199
https://www.purl.org/stefan_ram/pub/dual-band_if (permalink) is the canonical URI of this page.
Stefan Ram

A Dual-Band If-Statement in Java

This article features a pattern for a dual-band “if-statement” that allows concise notation of implementations of the following pseudocode instructions in Java. The author is not aware of having seen such a solution anywhere else yet (as of 2007-10-05).

The next three examples are pseudocode, expressing what one sometimes would like to do in Java. The rest of the article then will show, how this can indeed be written in a concise manner.

0) Attempt to calculate or do something
if( result = calculation( args )) ...

The result of the calculation will be assigned to the variable if the calculation attempt succeeded, and the statement »...« will be executed only in this case.

1) Implicit Actions at the end of a block (as in RAII )
{ openHTML( "ul" ); ... }

The call »openHTML( "ul" )« will emit code to open an HTML  element of type »ul«. After the execution of »...«, code to close the element will be emitted without an additional statement to do so at the end of the block.

2) Tests and downcasts within a single expression
if( string = instanceOfString( object )) ...

Here, the name »object« has the type »java.lang.Object« and the name »string« has the type »java.lang.String«. The reference contained in the variable »object« will be assigned to the variable »string« only if the object referenced by this reference is an instance of the class »java.lang.String«, and the following statement »...« will only be executed in this case.

The pattern being described also allows one to encapsulate resource handling in classes suitable for programming without jump-like statements, i.e., structured programming.

Very impatient readers might skip the next two sections and start reading at “Getting a Type by its Name With the Dual-Band If ”. However, it is recommended to take the time to read the next two sections, as they expose the problem, which then will be solved.

Attempts to Calculate Something

A calculation sometimes might either obtain a result or fail. For example, opening a file for reading might fail when the file does not exist.

In-band encoding of error codes uses a special result value to signal an error. This can be difficult and error prone and is not possible, when all values of a type might be valid results. Therefore, in Java, exceptions are used to report error states in an “out of band” manner.

However, sometimes an approach more in the sense of structured programming is preferred. Exceptions also enforce jump-like disruptions of control flow, which are not wanted sometimes.

An application of a hypothetical if-statement might look as follows.

hypothetical if-statement wanted
if( result = calculation() )...

One wants for this hypothetical if statement to respect two different return values  from the function: The first return value is a code to signal success of the calculation and is used by the if-statement to decide whether to execute the next statement. The second return code is the actual result of the calculation and is being assigned to the variable »result« if the calculation succeed. This article now will show how a slight variation of this hypothetical if-statement can actually implement such a behavior in Java.

Getting a Type by its Name in the Classical Way

As a first step toward the solution, a calculation with a status code for success is implemented. As an example, the operation to get a reference type by its name is chosen.

Main.java
class PossibleType
{ java.lang.Class type = null;
boolean succeeded = false; public PossibleType( final java.lang.String name )
{ try
{ this.type = java.lang.Class.forName( name );
this.succeeded = true; }
catch( final java.lang.ClassNotFoundException classNotFoundException ){} } public boolean isValid()
{ return this.succeeded; } public java.lang.Class value()
{ return this.type; }} class Main
{ public static void main( final java.lang.String args[] )
{ final PossibleType possibleType = new PossibleType( "java.lang.Object" );
if( possibleType.isValid() )
{ final java.lang.Class type = possibleType.value();
java.lang.System.out.println( type ); }}}
System.out
class java.lang.Object

The code in the method »main« avoids exception handling, which is encapsulated in the class »PossibleType«.

An exception report is suppressed here. This usually is considered bad style, but it is appropriate, when the exception is not an error, but a possible outcome that will be handled by the normal program logic.

An annoyance with this approach is that the client code is quite long. It is not just a single assignment within an if-statement: Two assignments outside of the if-statement are needed. It is this annoyance that will be removed in the next section.

Getting a Type by its Name With the Dual-Band If

The following code implements a means to get a type by a name (which might fail) in a way that can be called more easily than in the solution above.

Main.java
class Type
implements
java.util.Iterator<java.lang.Class>,
java.lang.Iterable<java.lang.Class>
{ java.lang.Class result = null;
boolean succeeded = false;
int called = 0; public Type( final java.lang.String name )
{ try
{ this.result = java.lang.Class.forName( name );
this.succeeded = true; }
catch( final java.lang.ClassNotFoundException classNotFoundException ){} } public void remove(){} public boolean hasNext()
{ boolean result = false;
switch( this.called )
{ case 0: { result = this.succeeded; break; }
case 1: { this.remove(); }}
if( this.called < java.lang.Integer.MAX_VALUE )++this.called;
return result; } public java.lang.Class next()
{ return this.result; } public java.util.Iterator<java.lang.Class> iterator()
{ return this; }} class Main
{ public static void main( final java.lang.String args[] )
{ for( final java.lang.Class type : new Type( "java.lang.Object" ))
java.lang.System.out.println( type ); }}
System.out
class java.lang.Object

Observe, how now the method »hasNext()« has taken the rôle of the method »isValid()« of the preceding example and how the method »next()« has taken the rôle of the call »value()« of the preceding example,

Implementing the interface »java.lang.Iterable« allows the client to express the same procedure as in the preceding section, but in a manner much more concise. The for statement, however, is not used as a loop here, but like an if statement.

The part »for( final java.lang.Class type : new Type( "java.lang.Object" ))« resembles the structure and simplicity of the hypothetical if-statement »if( final java.lang.Class type = type( "java.lang.Object" ))«. The colon looks similar to the equals sign. The word »for« here just does not represent a loop with multiple iterations anymore, but can be read with another meaning. In English, the word “for” can also be used in as in the phrase “for the case of …”, which expresses the same meaning as “if …”, so one can get used to read “for” as “for the case of” in such applications.

Moreover, it is perfectly legal and normal for any loop statement to be executed just once or never, so the for statement still is readable as a normal Java  statement to any Java  programmer who just sees it without additional explanation.

The class »Type«, of course, can now be hidden in a library and reused. So the actual application is just:

Main.java
class Main
{ public static void main( final java.lang.String args[] )
{ for( final java.lang.Class type : new Type( "java.lang.Object" ))
java.lang.System.out.println( type ); }}
System.out
class java.lang.Object

The reader can confirm now, that

We are even able to use a final assignment, which otherwise is difficult in the context of computations that throw exceptions.

This application of the for-statement here is called “dual-band if  ”, because it effectively is used like an if-statement, either executing the following statement or not, but not repeating this. The attribute “dual-band” designates that there are two paths (“bands”) for information from the single call: The result value (given by »next()«) and an out-of-band success status information (given by »hasNext()«).

Of course, dual-band if statements can be nested in a structured manner, for example, the following program will only print something after both dual-band if statements have succeeded

Main.java
class Main
{ public static void main( final java.lang.String args[] )
{ for( final java.lang.Class type : new Type( "java.lang.Object" ))
for( final java.lang.Class type1 : new Type( "java.lang.String" ))
java.lang.System.out.println( type + ", " + type1 ); }}
System.out
class java.lang.Object, class java.lang.String

The next sections of this article will show more applications of such a „dual-band if-statement“.

Releasing Resources (RAII  in Java )

Sometimes, resources are to be released at the end of the block, while it might be more readable to request this only once at the start of the block.

In Lisp, this can be done with means like »with-open-file«, in C++, it can be done with RAII.

In Java, it now also can be done with the dual-band if.

As an example, we here show how HTML  elements can be written, where the “release” operation is the termination of the element by a closing tag, which has to be emitted after the element was opened and all of its contents was being written.

Main.java
import java.lang.Void;
import static java.lang.System.out; class Element
implements
java.util.Iterator<Void>,
java.lang.Iterable<Void>
{ final java.lang.String argument;
java.lang.Void result = null;
boolean succeeded = false;
int called = 0; public Element( final java.lang.String argument )
{ this.argument = argument;
if( this.argument != null )
{ out.println( "<" + argument + ">" );
this.succeeded = true; }} public void remove()
{ out.println( "</" + argument + ">" ); } public boolean hasNext()
{ boolean result = false;
switch( this.called )
{ case 0: { result = this.succeeded; break; }
case 1: { this.remove(); }}
++this.called;
return result; } public java.lang.Void next()
{ return this.result; } public java.util.Iterator<java.lang.Void> iterator()
{ return this; }} public class Main
{ public static void main( final java.lang.String[] args )
{ for( Void ul : new Element( "ul" ))
{ for( Void li0 : new Element( "li" ))out.println( "Alpha" );
for( Void li1 : new Element( "li" ))out.println( "Beta" ); }}}
System.out
<ul>
<li>
Alpha
</li>
<li>
Beta
</li>
</ul>

Observe, how now the method »remove()« has taken the responsibility for the release of the resource allocated (here: the creation of the closing tag).

A dummy return value of type »java.lang.Void« was required to comply with the syntax rules. Still the text to open a new element »for( Void ul : new Element( "ul" ))« is quite short, and already contains the emission of the corresponding end-tag after the following block.

Here the dual-band property of the dual-band if is not actually used. Instead another of its properties is used: The ability to implicitly perform clean-up actions at the end of the clients statement.

In applications, often there will be a non-void  return value from a resource allocation, and the dual-band if will then be able to implicitly release the resource at the end of the block. In such cases the two properties of the dual-band if, i.e., the two bands and the ability to implicitly perform clean-up operations can be utilized in combination, resulting in a very concise notation of a test for success, an assignment and a clean-up operation into a single for-loop control header.

Alternatives

An else path to handle errors might be implemented as follows.

Main.java
/* The class "Type" is being declared here as above. */

class Main
{ public static void main( final java.lang.String args[] )
{ out: do
{ for( final java.lang.Class type : new Type( "java.lang.Object" ))
{ java.lang.System.out.println( type ); break out; }
java.lang.System.out.println( "Can't find class." ); }while( false ); }}
System.out
class java.lang.Object

The second print statement will only be executed when the attempt to get the type had failed.

Admittedly, this is less readable than an else-clause. Possibly, it might become more readable, once one has used it several times and becomes used to it.

Testing Types

The code to test for a type at runtime and then using a variable of the appropriate type also looks verbose and redundant in Java.

Main.java
class Main
{ public static void main( final java.lang.String args[] )
{ final java.lang.Object object = "string";
if( object instanceof java.lang.String )
{ final java.lang.String string =( java.lang.String )object;
java.lang.System.out.println( string ); }}}
System.out
string

Here, a test is performed and then a cast follows that contains information about the types, which was already given. This seems to be redundant, but can not be encapsulated easily into a class or method. Using the dual-band if, such an encapsulation becomes possible.

Main.java
class InstanceOfString
implements
java.util.Iterator<java.lang.String>,
java.lang.Iterable<java.lang.String>
{ java.lang.String result = null;
boolean succeeded = false;
int called = 0;

public InstanceOfString( final java.lang.Object object )
{ if( object instanceof java.lang.String )
{ this.result =( java.lang.String )object;
this.succeeded = true; }}

public void remove(){}

public boolean hasNext()
{ boolean result = false;
switch( this.called )
{ case 0: { result = this.succeeded; break; }
case 1: { this.remove(); }}
if( this.called < java.lang.Integer.MAX_VALUE )++this.called;
return result; }

public java.lang.String next()
{ return this.result; }

public java.util.Iterator<java.lang.String> iterator()
{ return this; }}

class Main
{ public static void main( final java.lang.String args[] )
{ final java.lang.Object object = "string";
for( final java.lang.String string : new InstanceOfString( object ))
{ java.lang.System.out.println( string ); }}}
System.out
string

Notice, that the print statement will be executed only if the “cast” indeed was successful.

Several such tests can be done in sequence if only one of them will be true. To skip unnecessary test, they can all be put in a labeled do-while-loop, which is left using a »break« as soon as such a “cast” has succeeded.

A more general class »InstanceOf« might be added to a library, where the class to cast to is being passed as an additional parameter.

Documenting the Semantics With Interfaces

The actual semantics of the for target can be specified with JavaDoc  by subclassing the interface »java.util.Iterator« and the interface »java.lang.Iterable« as follows.

Main.java
/** An attempt to obtain a result.
The attempt happens at object initialization.
The possible result then might be obtained from the object.
@author Stefan Ram
@version slr@2007-10-06T21:24:24+02:00 */ interface Attempt<T>
extends java.util.Iterator<T>
{ /** Returns <tt>true</tt> iff the attempt was successful and this operation
is called for the first time after object initialization.
This will return false, if the attempt was not succesful or if this
is not the first call of this operation {@code hasNext()} after object
initialization and true on the first call to this operation {@code hasNext()}
after an initialization with a successful attempt.
@return <tt>true</tt> iff the attempt was successful and this operation
is called for the first time after object initialization */
boolean hasNext(); /** Returns the result of the attempt.
@return the result of the attempt. */
T next(); /** Releases any resource obtained during the attempt or as as result
of the attempt including the result of {@code next()} itself, if this
is considered a resource.
@exception IllegalStateException (as in the super interface). */
void remove(); } /** Implementing this interface allows an object to be the target of
the "foreach" statement. */
interface Attemptable<T>
extends java.lang.Iterable<T>
{ /** Returns an Attempt object.
@return an Attempt object. */
Attempt<T> iterator(); } class InstanceOfString
implements
Attempt<java.lang.String>,
Attemptable<java.lang.String>
{ java.lang.String result = null;
boolean succeeded = false;
int called = 0; public InstanceOfString( final java.lang.Object object )
{ if( object instanceof java.lang.String )
{ this.result =( java.lang.String )object;
this.succeeded = true; }} public void remove(){} public boolean hasNext()
{ boolean result = false;
switch( this.called )
{ case 0: { result = this.succeeded; break; }
case 1: { this.remove(); }}
if( this.called < java.lang.Integer.MAX_VALUE )++this.called;
return result; } public java.lang.String next()
{ return this.result; } public Attempt<java.lang.String> iterator()
{ return this; }} class Main
{ public static void main( final java.lang.String args[] )
{ final java.lang.Object object = "string";
for( final java.lang.String string : new InstanceOfString( object ))
{ java.lang.System.out.println( string ); }}}
System.out
string

Closing Resources

The technique to release resource can not always be used directly to hide implementations of the operation »close()« of the interface »java.io.Closeable«, because this close operation might throw another exception itself, which needs to be taken care of. However, if the required actions are the same for several occasions, they might be defined once in the implementation of the interface »java.lang.Iterable«.

The following implementation of iterable objects shows how the client can provide three blocks in a structured exception-less manner to handle each of the three possible outcomes of the attempt to open and close a stream: success to open and close; success to open, but failure to close; and failure to open.

This is useful for followers of structured programming, who want to hide exceptions as early as possible and write as much structured code as possible. (Still, there is the possibility of runtime exceptions, so they can not be ignored altogether, even with encapsulation of the declared non-runtime exceptions.)

A failure to open is indicated by not executing the for-statement even once. A failure to close is indicated by executing the for statement a second time with a loop value of »null«.

Main.java
class FileInputStreamer
implements
java.util.Iterator<java.io.FileInputStream>,
java.lang.Iterable<java.io.FileInputStream>
{ final java.io.File argument;
java.io.FileInputStream result = null;
boolean succeeded = false;
int called = 0;
boolean failed = false;
int code = -1; /** @param code 0: only open, 1: open and close, 2: open, close and iterate. */
public FileInputStreamer( final java.io.File argument, final int code )
{ this.argument = argument;
this.code = code;
try
{ this.result = new java.io.FileInputStream( argument );
this.succeeded = true; }
catch( final java.io.FileNotFoundException fileNotFoundException )
{} } public FileInputStreamer( final java.lang.String argument, final int code )
{ this( new java.io.File( argument ), code ); } public void remove()
{ if( code > 0 )
{ try
{ this.result.close(); }
catch( final java.io.IOException iOException )
{ this.failed = true; }}} public boolean hasNext()
{ boolean result = false;
switch( this.called )
{ case 0: { result = this.succeeded; break; }
case 1:
{ this.remove();
if( code > 1 && this.failed )
{ this.result = null;
result = true; }}}
++this.called;
return result; } public java.io.FileInputStream next()
{ return this.result; } public java.util.Iterator<java.io.FileInputStream> iterator()
{ return this; }} class FileInputStreamOpenCloseAndNull
implements
java.lang.Iterable<java.io.FileInputStream>
{ private final FileInputStreamer streamer; public FileInputStreamOpenCloseAndNull( final java.io.File argument )
{ this.streamer = new FileInputStreamer( argument, 2 ); } public FileInputStreamOpenCloseAndNull( final java.lang.String argument )
{ this.streamer = new FileInputStreamer( argument, 2 ); } public java.util.Iterator<java.io.FileInputStream> iterator()
{ return this.streamer; }} public class Main
{ public static void main( final java.lang.String[] args )
{ boolean opened = false;
for
( final java.io.FileInputStream fileInputStream:
new FileInputStreamOpenCloseAndNull( "input.txt" ))
if( fileInputStream != null )
{ opened = true;
java.lang.System.out.println
( "File input stream opened successfully." ); }
else
{ java.lang.System.out.println
( "Error: can't close file input stream." ); }
if( !opened )
{ java.lang.System.out.println
( "Error: can't open file input stream." ); }}}

Is someone wanted to have the stream opened and closed, but does not care to learn about failures to close, this can be done as follows (given the above declaration of the class »FileInputStreamer«).

Main.java
class FileInputStreamOpenAndClose
implements
java.lang.Iterable<java.io.FileInputStream>
{ private final FileInputStreamer streamer; public FileInputStreamOpenAndClose( final java.io.File argument )
{ this.streamer = new FileInputStreamer( argument, 1 ); } public FileInputStreamOpenAndClose( final java.lang.String argument )
{ this.streamer = new FileInputStreamer( argument, 1 ); } public java.util.Iterator<java.io.FileInputStream> iterator()
{ return this.streamer; }} public class Main
{ public static void main( final java.lang.String[] args )
{ boolean opened = false;
for
( final java.io.FileInputStream fileInputStream:
new FileInputStreamOpenCloseAndNull( "input.txt" ))
{ opened = true;
java.lang.System.out.println
( "File input stream opened successfully." ); }
if( !opened )
{ java.lang.System.out.println
( "Error: can't open File input stream." ); }}}

If the client wants to close the resource in the usual Java  way at the end of the block statement, he has to remember to close and take care of the possible exceptions himself.

Main.java
class FileInputStreamOpen
implements
java.lang.Iterable<java.io.FileInputStream>
{ private final FileInputStreamer streamer; public FileInputStreamOpen( final java.io.File argument )
{ this.streamer = new FileInputStreamer( argument, 0 ); } public FileInputStreamOpen( final java.lang.String argument )
{ this.streamer = new FileInputStreamer( argument, 0 ); } public java.util.Iterator<java.io.FileInputStream> iterator()
{ return this.streamer; }} public class Main
{ public static void main( final java.lang.String[] args )
{ boolean opened = false;
for
( final java.io.FileInputStream fileInputStream:
new FileInputStreamOpenCloseAndNull( "input.txt" ))
{ opened = true;
java.lang.System.out.println
( "File input stream opened successfully." );
try
{ fileInputStream.close(); }
catch( final java.io.IOException iOException )
{ java.lang.System.out.println
( "Error: can't close file input stream." ); }}
if( !opened )
{ java.lang.System.out.println
( "Error: can't open file input stream." ); }}}

About this page, Impressum  |   Form for messages to the publisher regarding this page  |   "ram@zedat.fu-berlin.de" (without the quotation marks) is the email-address of Stefan Ram.   |   Beginning at the start page often more information about the topics of this page can be found. (A link to the start page appears at the very top of this page.)  |   Copyright 2004 Stefan Ram, Berlin. All rights reserved. This page is a publication by Stefan Ram. Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722199 stefan_ram:722199 slrprd, slrprdqxx, slrprddoc, slrprd722199, slrprddef722199, PbclevtugFgrsnaEnz

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten.
https://www.purl.org/stefan_ram/pub/dual-band_if