From: Richard Heathfield on
James Dow Allen wrote:

<snip>

> Well at least Heathfield and Seebs agree on *something*:
> We seek human cognitive advantage.

Actually, I think Seebs and I agree on a great deal. This happens to be
something about which we mostly disagree, but even then we can find
small but significant areas of agreement, if we look hard enough.

<snip>

> Mr. Heathfield, IIRC, hasn't actually deigned to post an alternative.

I'm reasonably sure I did deign to post an alternative. But I may not
have done. I may merely have posted an alternative.

To save me finding it, however, I'll very quickly and no doubt
erroneously reconstruct it:

found = 0;
for(x = 0; !found && x < xlim; x++)
{
for(y = 0; !found && y < ylim; y++)
{
for(z = 0; !found && z < zlim; z++)
{
if(haystack[x][y][z] == needle)
{
point_assign(p, x, y, z);
found = 1;
}
}
}
}
return found;

Laugh away, sirrah! :-)

<snip>

> Hope this helps,

Yup. Style arguments are always fun.

--
Richard Heathfield <http://www.cpax.org.uk>
Email: -http://www. +rjh@
"Usenet is a strange place" - dmr 29 July 1999
Sig line vacant - apply within
From: Willem on

Let's take your example to make my point:


Richard Heathfield wrote:
) found = 0;
) for(x = 0; !found && x < xlim; x++)
) {
) for(y = 0; !found && y < ylim; y++)
) {
) for(z = 0; !found && z < zlim; z++)
) {
) if(haystack[x][y][z] == needle)
) {
) point_assign(p, x, y, z);
) found = 1;
) }
) }
) }
) }
) return found;

The benefit of your code, you say, is that you only need to look at the
conditional in the for statement, to see when the loop will end, right ?

If a return in the middle of the loops were used, then you not only have
to look at the loop conditional, but also inside the body of the loop,
correct ?

Now, in your code, it ends when you reach the limit of the range,
or when this 'found' variable becomes true. But, and here's the point,
to find out what happens to this 'found' variable, you have to look
*at the body of the code*. Exactly the same thing you have to do when
you don't follow SESE. So, in fact, in *both* versions, you have to
look in the body. So that would make them roughly equivalent.

But, in the SESE version, you *first* have to look at the loop conditional
*first*, and then in addition to that, you have to look at the loop body,
and furthermore, you have to search for some arbitrary variable, instead
of one of a few well-defined words (return, break, goto, longjmp).

And, to top it off, any maintenance programmer worth his salt has seen
loops of the form 'for (i = 0; i < N; i++) {...}', and can tell almost
instantly that it's running i over the range [0..N), (just like the
BASIC version FOR i = 0 TO N, as a matter of fact).

Now, in SESE code, there are a lot of different ways to make it happen.
One way is to use a boolean flag. Another is to manipulate the loop
counters. Another is to use a temporary to hold the result and check
for that, and I'm sure that plenty more versions exist.

So that, in total, are _three_ reasons why the SESE version is more
difficult to understand.


PS: I saw that you acknowledged not having refuted any arguments, so
feel free to ignore this as well.


PPS: Yes, that 'PS' is baiting you. I very much dislike it when people
stop arguing their side with a notion of "we're not going to agree",
while there are sound, factual arguments on the table.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
From: Seebs on
On 2010-05-10, Richard Heathfield <rjh(a)see.sig.invalid> wrote:
> Actually, I think Seebs and I agree on a great deal. This happens to be
> something about which we mostly disagree, but even then we can find
> small but significant areas of agreement, if we look hard enough.

Yes.

> erroneously reconstruct it:
>
> found = 0;
> for(x = 0; !found && x < xlim; x++)
> {
> for(y = 0; !found && y < ylim; y++)
> {
> for(z = 0; !found && z < zlim; z++)
> {
> if(haystack[x][y][z] == needle)
> {
> point_assign(p, x, y, z);
> found = 1;
> }
> }
> }
> }
> return found;

> Laugh away, sirrah! :-)

Okay, let's compare this with:

for (x = 0; x < xlim; ++x) {
for (y = 0; y < ylim; ++y) {
for (z = 0; z < zlim; ++z) {
if (haystack[x][y][z] == needle) {
point_assign(p, x, y, z);
return 1;
}
}
}
}
return 0;

I consider this much, much, easier to read. It gains even more if we
use the original's "return &haystack[x][y][z]".

In this case, I think yours is pretty close, because "!found && " is itself
a bit of an idiom. However, I find the latter easier to understand because
it's unambigously "loop over the entire array, doing { if you found a match,
set something and return 1 }", while for yours, I have to model it cognitively
as "loop until either something happens or we have covered this whole range,
doing { loop either until something happens or we have covered this whole
range, doing { loop either until something happens or we have covered this
whole range, doing { if you found a match, set something, and set something
else } } }".

Because the test conditions aren't part of the standard "loop over array"
idiom, I have to track both parts of the test condition separately, and doing
that for three layers of looping chews up six short-term memory slots, and
the index variables use up three more, leaving me solidly past my short-term
memory budget without even looking at the inner loop. For the form using
the pure idiom, I'm only using three slots -- I have x, y, and z as "the
current indexes in the loop".

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-nospam(a)seebs.net
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
From: Leigh Johnston on
"Richard Heathfield" <rjh(a)see.sig.invalid> wrote in message
news:qpSdnTKKs5xY13XWnZ2dnUVZ8uudnZ2d(a)bt.com...
> To save me finding it, however, I'll very quickly and no doubt erroneously
> reconstruct it:
>
> found = 0;
> for(x = 0; !found && x < xlim; x++)
> {
> for(y = 0; !found && y < ylim; y++)
> {
> for(z = 0; !found && z < zlim; z++)
> {
> if(haystack[x][y][z] == needle)
> {
> point_assign(p, x, y, z);
> found = 1;
> }
> }
> }
> }
> return found;
>
> Laugh away, sirrah! :-)
>
> <snip>
>
>> Hope this helps,
>
> Yup. Style arguments are always fun.
>

It is not a matter of style, SESE is an anachronism, a relic of old
programming languages. Your SESE compliant version is more complex (extra
conditional variables and extra conditionals checking those extra
conditional variables and extra CPU instructions to implement those extra
conditionals) than using an early return with a SEME version. As Willem
mentions elsewhere you do not gain anything from your SESE version as you
have to read *both* the loop conditionals (all three of them) in addition to
the code which changes the extra conditional variable making your SESE
version harder to understand than an equivalent SEME version.

It is time to stop using old fashioned programming languages with their
baggage of old fashioned "idioms".

/Leigh

From: Dave Harris on
nathancbaker(a)gmail.com (Nathan) wrote (abridged):
> > Specifically, you need to be aware that
> > data[0][0].size() may be different to data[1][0].size() or
> > data[0][1].size(), and that any of them may be zero meaning
> > that (eg) data[0][0][0] does not exist and must not be accessed.
>
> [...]
> Value_t* MyClass::findValue(const Value_t& value)
> {
> size_t xyzMax = data.size() + data[xInd].size() + data[xInd]
> [yInd].size();
> for(size_t xInd = 0; xInd < xyzMax; ++xInd)
> {
> if(data[xInd] == value)
> return &data[xInd];
> }
>
> return 0;
> }

But this does not do the same thing at all. You have done what I warned
you against, which is suppose that data[0][0].size() is the same as
data[0][1].size().

You also assume the values are contiguous in memory, which won't be true
if the data[0] is a std::vector (and it is almost certainly some kind of
data structure; given that it defines the size() method it won't be a
plain array).

And you've introduced additional bugs, for example adding the sizes when
you need to multiply them. Your later code misses out some braces so that
the loop always terminates after one iteration. You don't declare or
initialise all your variables. Frankly, you are not gaining any
credibility here.


> [...]
> So,
>
> 3 loop constructs are reduced to 1
> 4 conditionals are reduced to 2
> 2 exit points are reduced to 1
>
> Simple, isn't it?

When you can solve the original problem correctly, we can talk about
whether your solution is simpler.

-- Dave Harris, Nottingham, UK.