[Tutor] Losing the expressiveness ofC'sfor-statement?/RESENDwith example

Michael Sparks ms at cerenity.org
Fri Aug 10 19:55:08 CEST 2007


Stephen,


I've come into this thread late, but it looks like you're lamenting the fact 
you can stipulate complex iterations on a single line, which can be nice. I'd 
not really missed this in several years of programming with python.

However, Your post is interesting because it raises a point I've personally 
not considered before.

Your example loops are:

for (node=start; value<threshold && node!=end; node=node->next) { ... }
for (i=30000; i>0; i=i/2) { ... }

The argument you got back is that this is just syntactic sugar for logic
along the lines of:

   node=start; 
   while value<threshold && node!=end:
       ...
       node=node->next

Which of course is true. However simply saying that does miss the fact
that it is syntactic sugar with a purpose. Syntactic sugar is generally added 
for one of two reasons - speed of coding, or clarity of coding. In this case 
it can be argued it does both, since it spells out the iterator algorithm 
clearly on a single line.

Specifically you can look at one line and see the loop logic. This is nowhere
near as clear with this form:
   node=start; 

   while value<threshold && node!=end:
       ...
       last = node # hypothetical confuddling line
       node=node->next

And its certainly not on one line.

If you still want to spell out the iteration in one location, then you're
right you do have to use a generator. However the fact that you can put a
def anyway means you can do this:

    start = getNodesFromSomewhere()
    def traverseNodes(start):
       node = start
       yield node
       while node.next:
           node = node.next
           yield node
    for node in traverseNodes(start):
       ...

Similarly you can do this:
    def bisectdown(i=30000):
       while i >0:
          yield i
          i = i/2
    for node in bisectdown(30000):
       ...

That said, I agree that its not as nice perhaps as C's compact one liner for 
each of these. 

HOWEVER, you can rebuild C's version: (or something close)

    import compiler
    def cfor(iter_name, args,locals):
        Y=[x.strip().rstrip() for x in args.split(";")]
        Y[0] = compiler.compile(Y[0], "__main__.py", "exec")
        Y[1] = compiler.compile(Y[1], "__main__.py", "eval")
        Y[2] = compiler.compile(Y[2], "__main__.py", "exec")
        Y.append( compiler.compile(iter_name, "__main__.py", "eval"))
        exec(Y[0],locals,locals)
        while eval(Y[1],locals,locals):
             yield eval(Y[3],locals,locals)
             exec(Y[2],locals,locals)

You can then use this as follows:
    max = 10
    for i in cfor("i", "i=30000; i>max; i=i/2",locals()):
        print i

And also:
    start = getNodesFromSomewhere()
    for node in cfor("n", "n=start; n.next is not None; n = node.next",
                     locals()):
        ...

That's potentially quite useful. Yes there's a little cruft there (locals()),
but its not hideously inefficient either because I've made sure we compile the
code fragments and run those.

Personally I think its not a huge loss, but if you do, then you can always 
reuse this cfor iterator if you like.

I disagree though regarding the idea that C's for syntax is a universal 
syntax. It isn't. It's a commonly understood syntax due to C derived 
languages (C/C++/Java), but far from universal. I've had to learn many 
different "for" syntaxes over many years for different languages.

Even then where a C-type loop is availabe, it isn't always idiomatic to use 
it. For example perl (which does have a C-type for loop) idiomatically uses
foreach extensively. And you also get *very* different iterative behaviour
in ruby.

Different languages have different concepts. Just because you can write one 
language like another doesn't mean you should. That said, given that maxim, 
it sounds like your beef with more with docs rather than the lack of the 
construct, asking "is this a problem normally", to which the answer is most 
definitely not, "what do people normally do", to which you have numerous 
replies - people either create an iterator (as you often would in C++ and 
Java) or use a while loop.

As for rudeness, bear in mind that text is a naturally harsh medium, and
also cultural norms are very different for different posters. One man's
polite behaviour is another man's gravest insult. No one means to be rude,
so it's worth remembering that. (And yes, I know, merely saying that can
be considered rude in itself in some cultures :-)

You found people rude, they found you rude. None of you intended to be,
and probably weren't from your own perspectives, that's what really matters.


Michael.


More information about the Tutor mailing list