Why not allow empty code blocks?

Steven D'Aprano steve at pearwood.info
Sat Jul 30 22:10:52 EDT 2016


On Sun, 31 Jul 2016 04:46 am, BartC wrote:

> On 30/07/2016 16:48, Steven D'Aprano wrote:
>> On Sat, 30 Jul 2016 11:58 pm, BartC wrote:
>>
>>> The 'i' is superfluous. Why not:
>>>
>>>   for 10:
>>
>> Why bother? What's so special about this that it needs dedicated syntax?
> 
> No named loop variable to invent, create, maintain, and destroy. No
> range object to create, destroy etc. If you're looking for ways for a
> language to be more efficient, then why disregard this possibility?

Who says I've disregarded it? Just because I've concluded that the benefit
fails to outweigh the costs doesn't mean I didn't think about it.

To be clear, it's not *my* decision whether or not Python gets this new
syntactic feature or that. But the same applies to the people (mostly
Guido) whose decision it is. Just because they come to the opposite
conclusion to you doesn't mean they haven't considered alternatives.


[...]
> But I'm sure you have needed, at
> some time or other, infinite loops or repeat N times loops. And then you
> just emulate them as best you can with 'while 1:' or 'for _ in
> range(N):' or whatever.

"As best you can" sounds second best. How about we say *better* instead?

"while True" doesn't merely emulate an infinite loop, it implements an
infinite loop without needing dedicated syntax, byte-code or
implementation. Infinite loops are not conceptually different from finite
loops, they're just ordinary while loops where the condition is always
true.

If you say to me that a dedicated infinite loop construct can save a
comparison each time round, I'll have two responses:

(1) That's close to the worst example of premature optimization I've ever
seen. Outside of artificial and trivial benchmarks involving do-nothing or
do-almost-nothing loops, in what real-world situation is the difference
between:

    do forever:  # no comparison made
        block

and

    do while True  # always checks that the constant True is, in fact, True
        block

going to be significant? The *MOST* you are going to save will be a
conditional test (in Python, that will probably be based on a pointer
comparison, or something equivalently cheap) before the jump.


(2) And even if it is significant, surely that's something that a keyhole
optimizer can detect without requiring the user to care one iota about the
difference? And indeed, that's EXACTLY what Python 3.6 (and probably older
versions) does: it optimizes out the comparison, and unconditionally loops:

py> from dis import dis
py> dis("while flag: spam()")
  1           0 SETUP_LOOP              14 (to 16)
        >>    2 LOAD_NAME                0 (flag)
              4 POP_JUMP_IF_FALSE       14
              6 LOAD_NAME                1 (spam)
              8 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
             10 POP_TOP
             12 JUMP_ABSOLUTE            2
        >>   14 POP_BLOCK
        >>   16 LOAD_CONST               0 (None)
             18 RETURN_VALUE
py> dis("while True: spam()")
  1           0 SETUP_LOOP              10 (to 12)
        >>    2 LOAD_NAME                0 (spam)
              4 CALL_FUNCTION            0 (0 positional, 0 keyword pair)
              6 POP_TOP
              8 JUMP_ABSOLUTE            2
             10 POP_BLOCK
        >>   12 LOAD_CONST               0 (None)
             14 RETURN_VALUE


 
> But dedicated forms (even if they just map to 'while' or 'for') wouldn't
> hurt. Syntax is free after all, and it's about expressing exactly what
> you mean.

Syntax is not free!

Syntax requires more code in the compiler. Somebody has to write it,
somebody has to maintain it, somebody has to test it, somebody has to
document it.

When you offer a choice between two or more features which do the same
thing, say a general case and a dedicated special case, your users have to
learn them both. They have to understand the difference between them, and
they have to choose which to use. And they invariably have to deal with
code by others which chooses "wrongly" according to the user's own values.

Every little feature increases the size of the compiler, both the source and
binary, and increases the chances of compiler bugs. There are already
situations where compilers are too big (e.g. on embedded devices, or
memory- and storage-constrained machines like the RaspberryPy). It adds to
the time it takes to download, adds to the time it takes to build the
compiler, adds to the time to test the compiler, and adds to the time it
takes to compile your code. It increases the compiler complexity, and
having dedicated opcodes may rule out certain JIT optimization strategies.

You're perfectly welcome to decide that you consider those costs to be
negligible, especially for a language that has a user-base of one, namely
yourself. That's your value judgement. Others may judge differently.




-- 
Steven
“Cheer up,” they said, “things could be worse.” So I cheered up, and sure
enough, things got worse.




More information about the Python-list mailing list