Re: on goto
* Howard Hinnant:
Everyone knows goto is evil. Modern languages like Java have been
able to completely eliminate goto! Instead they use much superior
language tools such as labeled breaks:
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/branch.html
Fortunately C/C++ is powerful enough that it can very closely emulate
this far superior Java language feature. Here is the code snippet
from the java tutorial demonstrating labeled breaks translated to C++,
using a new and improved "labeled_break" statement:
#define RCONCAT(x,y) y##x
#define labeled_break(x) RCONCAT(to, go) x
...
search:
for (i = 0; i < arrayOfInts.length; i++) {
for (j = 0; j < arrayOfInts[i].length; j++) {
if (arrayOfInts[i][j] == searchfor) {
foundIt = true;
labeled_break( search );
}
}
}
One should always use this labeled_break facility instead of the
extremely evil and error prone goto!
Oh dear. I've been trying, really trying, to mark this thread "read" every time
I let my Thunderbird out to flap her wings. But, anyway, I'm afraid the
labeled_break implementation above is a bit too /roundabout/ for my liking, sort
of, my head spins in a loop just thinking about it.
Here's my more direct take on it.
It's not perfect, but hey!
<code>
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <stdexcept>
#include <stddef.h>
#include <assert.h>
typedef ptrdiff_t Size;
typedef Size Index;
typedef std::string String;
template< typename T >
class Array
{
private:
std::vector< T > myItems;
Size getLength() const { return myItems.size(); }
struct LengthProperty
{
Array* a;
LengthProperty( Array& arr ): a( &arr ) {}
operator Size() const { return a->getLength(); }
};
public:
LengthProperty length;
Array(): length( *this ) {}
T& operator[]( Index i ) { return myItems.at( i ); }
T const& operator[]( Index i ) const { return myItems.at( i ); }
Array& operator<<( T const& v )
{
myItems.push_back( v );
return *this;
}
};
struct Success {};
struct Failure {};
bool fail() { throw Failure(); }
namespace sys { namespace out {
void println( String const& s )
{
std::cout << s << std::endl;
}
} } // namespace sys::out
class S
{
private:
std::ostringstream stream;
public:
template< typename T >
S& operator<<( T const& v )
{
stream << v;
return *this;
}
operator String() const { return stream.str(); }
};
int main()
{
typedef Array< int > IntArray;
typedef Array< IntArray > IntMatrix;
IntMatrix const arrayOfInts = IntMatrix()
<< ( IntArray() << 32 << 87 << 3 << 589 )
<< ( IntArray() << 12 << 1076 << 2000 << 8 )
<< ( IntArray() << 622 << 127 << 77 << 955 );
int const searchFor = 12;
int i;
int j;
try
{
for( i = 0; i < arrayOfInts.length || fail(); ++i )
{
for( j = 0; j < arrayOfInts[i].length; ++j )
{
if( arrayOfInts[i][j] == searchFor )
{
throw Success();
}
}
}
assert( false );
}
catch( Success )
{
sys::out::println(
S() << "Found " << searchFor << " at " << i << ", " << j
);
}
catch( Failure )
{
sys::out::println( S() << searchFor << " not in the array" );
}
}
</code>
I think, one should always use this very clear Success/Failure combo instead of
the extremely evil and error prone "goto" or boolean variable! ;-)
Cheers,
- Alf
PS: Do you think the comma operator could help?