From: S Perryman on
Juha Nieminen wrote:

> Care to show an actual example of your "simpler, cleaner and easier to
> follow" version of exiting a nested loop by meddling with the loop
> conditions instead of using 'return'? For example, modify the following
> code to conform to your specifications:

> Value_t* MyClass::findValue(const Value_t& value)
> {
> for(size_t xInd = 0; xInd < data.size(); ++xInd)
> for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
> for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
> {
> if(data[xInd][yInd][zInd] == value)
> return &data[xInd][yInd][zInd];
> }

> return 0;
> }


Was directed here as I'm known to my colleagues as a "single entry single
exit" devotee, and twas said you had an interesting challenge ...


1. A "like for like" equivalent of your example is (braces inserted
because that is the convention I use) :


Value_t*
MyClass::findValue(const Value_t& value)
{
Value_t* RESULT = 0 ;

for(size_t xInd = 0; xInd < data.size(); ++xInd)
{
for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
{
for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
{
if(data[xInd][yInd][zInd] == value)
{
RESULT = &data[xInd][yInd][zInd] ;

// Termination states for the xInd/yInd/zInd loops
xInd = data.size() - 1 ;
yInd = data[xInd].size() - 1 ;
zInd = data[xInd][yInd].size() - 1 ;
}
}
}
}

return RESULT ;
}


2. To make the above more acceptable in terms of "Hoare logic" :

Value_t*
MyClass::findValue(const Value_t& value)
{
Value_t* RESULT = 0 ;

boolean found = false ;
size_t x = 0;
size_t y = 0;
size_t z = 0;

for(size_t xInd = 0; xInd < data.size(); ++xInd)
{
for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
{
for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
{
if(data[xInd][yInd][zInd] == value)
{
found = true ;
x = xInd ;
y = yInd ;
z = zInd ;

// Termination states for the xInd/yInd/zInd loops
xInd = data.size() - 1 ;
yInd = data[xInd].size() - 1 ;
zInd = data[xInd][yInd].size() - 1 ;
}
}
}
}

// found OR (x = y = z = 0)
// FORALL found :
// x < data.size() , y < data[x].size() , z < data[x][y].size()
if(found) { RESULT = &data[x][y][z] ; }


return RESULT ;
}


Differences in code size are evident at the source code level.

Differences in efficiency are negligible ?? (cost of 5 assignments for #1,
13 assignments + 1 boolean flag test for #2) .

#1 does not appear to be that difficult to understand.
#2 shows that reasoned correctness (Hoare logic etc) does not come for
free.


Regards,
Steven Perryman
From: Ben Bacarisse on
S Perryman <q(a)q.net> writes:

> Juha Nieminen wrote:
>
>> Care to show an actual example of your "simpler, cleaner and easier to
>> follow" version of exiting a nested loop by meddling with the loop
>> conditions instead of using 'return'? For example, modify the following
>> code to conform to your specifications:
>
>> Value_t* MyClass::findValue(const Value_t& value)
>> {
>> for(size_t xInd = 0; xInd < data.size(); ++xInd)
>> for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
>> for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
>> {
>> if(data[xInd][yInd][zInd] == value)
>> return &data[xInd][yInd][zInd];
>> }
>
>> return 0;
>> }

<snip re-write number 1>

> 2. To make the above more acceptable in terms of "Hoare logic" :
>
> Value_t*
> MyClass::findValue(const Value_t& value)
> {
> Value_t* RESULT = 0 ;
>
> boolean found = false ;
> size_t x = 0;
> size_t y = 0;
> size_t z = 0;
>
> for(size_t xInd = 0; xInd < data.size(); ++xInd)
> {
> for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
> {
> for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
> {
> if(data[xInd][yInd][zInd] == value)
> {
> found = true ;
> x = xInd ;
> y = yInd ;
> z = zInd ;
>
> // Termination states for the xInd/yInd/zInd loops
> xInd = data.size() - 1 ;
> yInd = data[xInd].size() - 1 ;
> zInd = data[xInd][yInd].size() - 1 ;
> }
> }
> }
> }
>
> // found OR (x = y = z = 0)
> // FORALL found :
> // x < data.size() , y < data[x].size() , z < data[x][y].size()

[Aside: in case anyone thinks this is all the loop establishes the key
result is that found => data[x][y][z] = value and that !found => forall
i, j, k in range data[i][j][k] != value. Depending on what you are
using this for you might also want to show that (x, y, z) is the
smallest tuple s.t. data[i][j][k] != value.]

> if(found) { RESULT = &data[x][y][z] ; }
>
> return RESULT ;
> }
<snip>

If you twisted my arm, I'd be tempted by:

Value_t *MyClass::findValue(const Value_t &value)
{
size_t xInd = 0, yInd = 0, zInd = 0;

while (xInd < data.size() && data[xInd][yInd][zInd] != value) {
if (++zInd == data[xInd][yInd].size()) {
zInd = 0;
if (++yInd == data[xInd].size()) {
yInd = 0;
++xInd;
}
}
}

return xInd == data.size() ? 0 : &data[xInd][yInd][zInd];
}

--
Ben.
From: S Perryman on
Ben Bacarisse wrote:

> S Perryman <q(a)q.net> writes:

>>2. To make the above more acceptable in terms of "Hoare logic" :
>>
>>Value_t*
>>MyClass::findValue(const Value_t& value)
>>{
>> Value_t* RESULT = 0 ;
>>
>> boolean found = false ;
>> size_t x = 0;
>> size_t y = 0;
>> size_t z = 0;
>>
>> for(size_t xInd = 0; xInd < data.size(); ++xInd)
>> {
>> for(size_t yInd = 0; yInd < data[xInd].size(); ++yInd)
>> {
>> for(size_t zInd = 0; zInd < data[xInd][yInd].size(); ++zInd)
>> {
>> if(data[xInd][yInd][zInd] == value)
>> {
>> found = true ;
>> x = xInd ;
>> y = yInd ;
>> z = zInd ;
>>
>> // Termination states for the xInd/yInd/zInd loops
>> xInd = data.size() - 1 ;
>> yInd = data[xInd].size() - 1 ;
>> zInd = data[xInd][yInd].size() - 1 ;
>> }
>> }
>> }
>> }
>>
>> // found OR (x = y = z = 0)
>> // FORALL found :
>> // x < data.size() , y < data[x].size() , z < data[x][y].size()
>
>
> [Aside: in case anyone thinks this is all the loop establishes the key
> result is that found => data[x][y][z] = value

Correct.


> and that !found => forall
> i, j, k in range data[i][j][k] != value. Depending on what you are
> using this for you might also want to show that (x, y, z) is the
> smallest tuple s.t. data[i][j][k] != value.]

Which completes the correctness spec for the search.


#1 has an issue, since it uses the same termination state for both
successful and unsuccessful searches. Hence the reason for showing #2.


Regards,
Steven Perryman
From: James Dow Allen on
On May 17, 6:03 pm, S Perryman <q...(a)q.net> wrote:
> #1 does not appear to be that difficult to understand.

Sorry to repeat myself here (although that hasn't stopped
some of the rest of you :-) but this whole dialog continues
to stagger my imagination!

No, #1 isn't "too difficult" to understand ... but it *is*
more difficult than the simpler, more obvious approach.

Another grown man felt the need to post flowchart
comparisons that blithely ignored that (A && B)
is more "complicated" than (B). If it isn't clear what
I'm driving at then run this code through your "tool":
A = B ? C : D;

if (B)
AA = C;
else
AA = D;
If your tool tells you the first form above is simpler,
would you agree the tool is flawed?

I am not alone in thinking that the simpler coding is,
in this case, clearly best. I can't imagine how to interpret
opposition except as "overly dogmatic."

Hope this helps,
James Dow Allen
From: bart.c on
James Dow Allen wrote:
> On May 17, 6:03 pm, S Perryman <q...(a)q.net> wrote:
>> #1 does not appear to be that difficult to understand.
>
> Sorry to repeat myself here (although that hasn't stopped
> some of the rest of you :-) but this whole dialog continues
> to stagger my imagination!
>
> No, #1 isn't "too difficult" to understand ... but it *is*
> more difficult than the simpler, more obvious approach.
>
> Another grown man felt the need to post flowchart
> comparisons that blithely ignored that (A && B)
> is more "complicated" than (B). If it isn't clear what
> I'm driving at then run this code through your "tool":
> A = B ? C : D;
>
> if (B)
> AA = C;
> else
> AA = D;
> If your tool tells you the first form above is simpler,
> would you agree the tool is flawed?

AA?

Whether A or AA, this potentially complex term has to be repeated. This form
also encourages you to spread it over 4 lines instead of 1, which can have
the effect of expanding the surrounding statement or function enough to make
it harder to take in at a glance.

--
Bartc