Code block literals

Dave Benjamin dave at 3dex.com
Wed Oct 8 23:01:02 EDT 2003


Mike Rovner wrote:

> Dave Benjamin wrote:
> 
>>For instance, I always thought this was a cooler alternative to the
>>try/finally block to ensure that a file gets closed (I'll try not to
>>mess up this time... ;) :
>>
>>open('input.txt', { |f|
>>     do_something_with(f)
>>     do_something_else_with(f)
>>})
>>
>>Rather than:
>>
>>f = open('input.txt')
>>try:
>>     do_something_with(f)
>>     do_something_else_with(f)
>>finally:
>>     f.close()
> 
> "Explicit is better than implicit"

In that case, why do we eschew code blocks, yet have no problem with the 
implicit invocation of an iterator, as in:

for line in file('input.txt'):
     do_something_with(line)

This is not to say that I dislike that behavior; in fact, I find it 
*beneficial* that the manner of looping is *implicit* because you can 
substitute a generator for a sequence without changing the usage. But 
there's little readability difference, IMHO, between that and:

file('input.txt').each_line({ |line|
     do_something_with(line)
})

Plus, the first example is only obvious because I called my iteration 
variable "line", and because this behavior is already widely known. What 
if I wrote:

for byte in file('input.dat'):
     do_something_with(byte)

That would be a bit misleading, no? But the mistake isn't obvious. OTOH, 
in the more explicit (in this case) Ruby language, it would look silly:

open('input.txt').each_line { |byte|
     # huh? why a byte? we said each_line!
}

I think this is important to point out, because the implicit/explicit 
rule comes up all the time, yet Python is implicit about lots of things! 
To name a few:

   - for loops and iterators
   - types of variables
   - dispatching via subclass polymorphism
   - coercion (int->float, int->long...)
   - exceptions (in contrast with Java's checked exceptions)
   - __magic_methods__
   - metaclasses
   - nested scopes (compared to yesteryear's lambda x, y=y, z=z: ...)
   - list comprehensions

In all of the above cases (with a bit of hesitation toward the voodoo of 
metaclasses) I think Python is a better language for it. On the other 
hand, Perl's implicit $_ variable is a good example of the hazards of 
implicitness; that can be downright confusing. So, it's not cut and dry 
by any means.

If all you're saying is that naming something is better than not naming 
something because explicit is better than implicit, I'd have to ask why:

a = 5
b = 6
c = 7
d = a + b
e = c / 2
result = d + e
return result

Is any better than:

...
return (a + b) + (c / 2)

To me, it's the same issue. Why should I have to name something that I'm 
just going to return in the next statement, or pass as a parameter, and 
then be done with it? Does that really increase either readability or 
understandability? Why should I name something that I'm not going to ask 
for later?

> Even your example clearly shows that try block is much more readable and
> understandable.
> That's why it's being considered evil by majority of python developers.

Readability is a moving target. I think that the code block syntax 
strikes a nice balance between readability and expressiveness. As far as 
what the majority of Python developers consider evil, I don't think 
we've got the stats back on that one.

>>But the anonymous version still looks more concise to me.
> 
> Python prioritize things diferently than other languages.
> It's not an APL. "Readability counts"

This is nothing like APL... if anything, it's like Smalltalk, a language 
designed to be readable by children! I realize that APL sacrificed 
readability for expressiveness to an uncomfortable extreme, but I really 
think you're comparing apples and oranges here. List comprehensions are 
closer to APL than code blocks.

Dave





More information about the Python-list mailing list