Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Why not allow empty code blocks?

515 views
Skip to first unread message

Kent Tong

unread,
Jul 22, 2016, 11:33:28 AM7/22/16
to
Hi

I'm aware that we can use 'pass' as an empty code block. But why doesn't python allow a code block to be empty and thus eliminate the need for this null statement?

thanks in advance

Rob Gaddi

unread,
Jul 22, 2016, 12:44:58 PM7/22/16
to
Because it's more likely that you have an indentation error than an
intentional need for an empty code block, and Python's trying to prevent
you shooting yourself in the foot. If you actually needed an empty code
block, the langugage provides a way of marking that emptyness as
intentional. That way is the pass statement.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com

Email address domain is currently out of order. See above to fix.

Steven D'Aprano

unread,
Jul 22, 2016, 9:49:51 PM7/22/16
to
Because it cannot tell the difference between an empty code block and
failing to indent the code block:

for x in sequence:
print('loop')


Is that meant to print 'loop' each time around the loop, or just once, at
the end of the loop?

There are cases where the interpreter could tell:


if flag:
else:
block


Obviously the "if" block is empty. But for consistency, and simplicity, the
interpreter requires a pass there too. One less thing to be programmed, one
less thing for the user to remember. Just require pass any time you have an
empty block, rather than try to remember where it is required and were it
is optional.




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

Kent Tong

unread,
Jul 22, 2016, 10:06:52 PM7/22/16
to
On Saturday, July 23, 2016 at 9:49:51 AM UTC+8, Steven D'Aprano wrote:

> Because it cannot tell the difference between an empty code block and
> failing to indent the code block:
>
> for x in sequence:
> print('loop')

Thanks for the excellent answer!

Marko Rauhamaa

unread,
Jul 23, 2016, 7:14:00 AM7/23/16
to
Steven D'Aprano <st...@pearwood.info>:

> On Sat, 23 Jul 2016 01:33 am, Kent Tong wrote:
>> I'm aware that we can use 'pass' as an empty code block. But why
>> doesn't python allow a code block to be empty and thus eliminate the
>> need for this null statement?
>
> Because it cannot tell the difference between an empty code block and
> failing to indent the code block:
>
> for x in sequence:
> print('loop')
>
> Is that meant to print 'loop' each time around the loop, or just once, at
> the end of the loop?

I don't see an ambiguity: obviously the print call takes place after
finishing the loop.

> There are cases where the interpreter could tell:
>
> if flag:
> else:
> block
>
> Obviously the "if" block is empty. But for consistency, and
> simplicity, the interpreter requires a pass there too.

I wonder if there is any true case of ambiguity. I guess this is all
about an enforced aesthetic principle: GvR doesn't like the looks of an
empty block.

> One less thing to be programmed, one less thing for the user to
> remember. Just require pass any time you have an empty block, rather
> than try to remember where it is required and were it is optional.

Actually, the requirement of a dummy statement is a slight annoyance for
the programmer. After deleting a statement, you must see if you have to
put in a pass statement. And after adding a statement, you may feel the
urge to remove the redundant pass statement.


Marko

Chris Angelico

unread,
Jul 23, 2016, 7:35:03 AM7/23/16
to
On Sat, Jul 23, 2016 at 9:13 PM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>> One less thing to be programmed, one less thing for the user to
>> remember. Just require pass any time you have an empty block, rather
>> than try to remember where it is required and were it is optional.
>
> Actually, the requirement of a dummy statement is a slight annoyance for
> the programmer. After deleting a statement, you must see if you have to
> put in a pass statement. And after adding a statement, you may feel the
> urge to remove the redundant pass statement.

How often do you actually need empty statements, adding stuff,
removing stuff, like that? Possibly there's a code smell here.

ChrisA

Marko Rauhamaa

unread,
Jul 23, 2016, 7:49:16 AM7/23/16
to
Chris Angelico <ros...@gmail.com>:
Quite often. For example:

class ItHitFan(Exception): pass

==>

class ItHitFan(Exception):
def __init__(self, huh):
super().__init__()
self.huh = huh


Marko

Rustom Mody

unread,
Jul 23, 2016, 8:28:47 AM7/23/16
to
On Saturday, July 23, 2016 at 4:44:00 PM UTC+5:30, Marko Rauhamaa wrote:
> Steven D'Aprano :
Tsk Tsk…
The Europeans took 500 years to appreciate that zero is a necessity
https://en.wikipedia.org/wiki/Arabic_numerals#Adoption_in_Europe

Do you seriously suppose that they did not have the asymptotic/limiting case of:

There are 3 apples in the basket
There are 2 apples in the basket
There are 1 apples in the basket

Now you can (and they probably did) replace the ‘1’ by ‘no’
But that’s not a number
You can have nothing there:
There are apples in the basket
Is it visible?

Problem is more evident if we use a ‘base-1’ system
There are XXX apples in the basket
There are XX apples in the basket
There are X apples in the basket
There are apples in the basket

IOW the notion of zero is trivial enough (in hindsight)
First-classing it as a notation is not at all trivial

This question is analogous – maybe almost identical – to the question of
the most trivial automata/regex etc.

For a long time the re → dfa transformation went and was taught the laborious
route:
re → nfa-with-ε-transitions → nfa-without-ε-transitions → dfa

https://en.wikipedia.org/wiki/Thompson's_construction
https://en.wikipedia.org/wiki/Powerset_construction

Now there is a direct, straightforward method which only becomes available
(thinkable) when we have a null regular expression:
https://drona.csa.iisc.ernet.in/~deepakd/fmcs-06/seminars/presentation.pdf

Coming back to zero:
While it is true that European civilization knew of and ignored the zero for
500 years and science-advances happened only after adopting zero, and today
we take it for granted. Still it remains true that zero is a bit anomalous.

Some evidences of this:
Lets say that a numeral is in normal form if it has no leading zeros.
So 0025 normalizes to 25.

Is 0 a normal form?

Likewise: Early versions of Fortran had loops that could not execute zero times:
http://www-pnp.physics.ox.ac.uk/~gronbech/intfor/node18.html

In the same vein «pass» (Dijkstra called it «skip») and «abort» (roughly «raise Exception» in python-speak) correspond to 1 and 0 in numbers

And IMHO anyone who rejects the search/formalization for the trivial case as a
useless activity is effectively pushing us back to the dark ages.
And if one finds it hard to believe that humans can be incredibly resistant
to learning from mistakes, here's a list of long-lasting errors like rejecting zero:
http://blog.languager.org/2016/01/how-long.html

D'Arcy J.M. Cain

unread,
Jul 23, 2016, 8:30:05 AM7/23/16
to
On Sat, 23 Jul 2016 14:13:46 +0300
Marko Rauhamaa <ma...@pacujo.net> wrote:
> > for x in sequence:
> > print('loop')
> >
> > Is that meant to print 'loop' each time around the loop, or just
> > once, at the end of the loop?
>
> I don't see an ambiguity: obviously the print call takes place after
> finishing the loop.

It's ambiguous to the reader what was actually meant. Forcing a "pass"
there shows the reader that the empty block was not a mistake.
Explicit is better than implicit.

> I wonder if there is any true case of ambiguity. I guess this is all
> about an enforced aesthetic principle: GvR doesn't like the looks of
> an empty block.

I don't think that he would be alone.

> Actually, the requirement of a dummy statement is a slight annoyance
> for the programmer. After deleting a statement, you must see if you
> have to put in a pass statement. And after adding a statement, you
> may feel the urge to remove the redundant pass statement.

If you allow empty blocks and you use it I hope that you would add a
comment so that the reader knows that you meant it.

for x in sequence: # this is an empty block

Is that better than "pass"?

--
D'Arcy J.M. Cain
System Administrator, Vex.Net
http://www.Vex.Net/ IM:da...@Vex.Net
VoIP: sip:da...@Vex.Net

Marko Rauhamaa

unread,
Jul 23, 2016, 9:14:10 AM7/23/16
to
"D'Arcy J.M. Cain" <da...@Vex.Net>:

> On Sat, 23 Jul 2016 14:13:46 +0300
> Marko Rauhamaa <ma...@pacujo.net> wrote:
>> I don't see an ambiguity: obviously the print call takes place after
>> finishing the loop.
>
> It's ambiguous to the reader what was actually meant. Forcing a "pass"
> there shows the reader that the empty block was not a mistake.

Just let the syntax speak for itself. The code means what the language
definition says it means.

>> I wonder if there is any true case of ambiguity. I guess this is all
>> about an enforced aesthetic principle: GvR doesn't like the looks of
>> an empty block.
>
> I don't think that he would be alone.

Then just appeal to that subjective preference instead of some objective
necessity.

BTW, the standard shell requires a dummy statement in a block even
though the block boundaries are clearly marked:

while not quit; do
done

is a syntax error. This works:

while not quit; do
:
done

> If you allow empty blocks and you use it I hope that you would add a
> comment so that the reader knows that you meant it.

Once you learn the idioms of a language, you don't need to comment the
obvious.

> for x in sequence: # this is an empty block
>
> Is that better than "pass"?

Er, in that hypothetical world, the right answer would be simply:

for x in sequence:


Note that I'm not arguing for the removal of "pass." I'm just saying
it isn't strictly necessary.


Marko

D'Arcy J.M. Cain

unread,
Jul 23, 2016, 9:55:01 AM7/23/16
to
On Sat, 23 Jul 2016 16:13:58 +0300
Marko Rauhamaa <ma...@pacujo.net> wrote:
> "D'Arcy J.M. Cain" <da...@Vex.Net>:
> > It's ambiguous to the reader what was actually meant. Forcing a
> > "pass" there shows the reader that the empty block was not a
> > mistake.
>
> Just let the syntax speak for itself. The code means what the language
> definition says it means.

Exactly so given this...

for x in sequence:
print("Something")

If the language allowed that then we know exactly what the programmer
said. What we don't know is what the programmer meant. The above is a
simple and obvious statement but real code is more complicated. Add a
few comments and a little nesting and what used to be obvious isn't.
The interpreter would still know what the programmer said but without
the pass requirement it is easier for it to be not what he meant.

Python has some nice features like this one that protect the programmer
and allow much faster development because there is a safety net. If
you like knives without handles you know where to find Perl.

Gotta go. The metaphor police are at the door.

BartC

unread,
Jul 23, 2016, 10:00:28 AM7/23/16
to
All the time?

For example when creating a set of empty functions to be populated
later, or empty branches of if and so on to be filled in as so you go.

Or, for debugging or other reasons, when you need to comment out the
contents of a block. Then pass needs to be added.

However in the absence of a strong end-of-block indicator and having to
infer the end of the block from what may or may not follow, then pass is
useful when the block is empty. But I don't think it needed to be mandatory.

--
Bartc

BartC

unread,
Jul 23, 2016, 10:07:07 AM7/23/16
to
On 23/07/2016 14:54, D'Arcy J.M. Cain wrote:
> On Sat, 23 Jul 2016 16:13:58 +0300
> Marko Rauhamaa <ma...@pacujo.net> wrote:
>> "D'Arcy J.M. Cain" <da...@Vex.Net>:
>>> It's ambiguous to the reader what was actually meant. Forcing a
>>> "pass" there shows the reader that the empty block was not a
>>> mistake.
>>
>> Just let the syntax speak for itself. The code means what the language
>> definition says it means.
>
> Exactly so given this...
>
> for x in sequence:
> print("Something")
>
> If the language allowed that then we know exactly what the programmer
> said. What we don't know is what the programmer meant. The above is a
> simple and obvious statement but real code is more complicated. Add a
> few comments and a little nesting and what used to be obvious isn't.
> The interpreter would still know what the programmer said but without
> the pass requirement it is easier for it to be not what he meant.
>
> Python has some nice features like this one that protect the programmer
> and allow much faster development because there is a safety net. If
> you like knives without handles you know where to find Perl.

pass can only do so much. If doesn't help here:

for x in sequence:
print("Something")
print("Something else")

Was the second print meant to be indented as well or not?

Perhaps rather than 'pass', the language ought to have provided an
optional 'end' keyword to mark the end of a block. Then there would be
less speculation about what was meant:

for x in sequence:
print("Something")
end
print("Something else")

(And no speculation at all if 'end' was mandatory. Python already
provides 'else' (and 'except'?) which can do a similar job in some
circumstances.)

--
Bartc

Chris Angelico

unread,
Jul 23, 2016, 10:19:37 AM7/23/16
to
On Sun, Jul 24, 2016 at 12:00 AM, BartC <b...@freeuk.com> wrote:
> On 23/07/2016 12:34, Chris Angelico wrote:
>>
>> On Sat, Jul 23, 2016 at 9:13 PM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>>>>
>>>> One less thing to be programmed, one less thing for the user to
>>>> remember. Just require pass any time you have an empty block, rather
>>>> than try to remember where it is required and were it is optional.
>>>
>>>
>>> Actually, the requirement of a dummy statement is a slight annoyance for
>>> the programmer. After deleting a statement, you must see if you have to
>>> put in a pass statement. And after adding a statement, you may feel the
>>> urge to remove the redundant pass statement.
>>
>>
>> How often do you actually need empty statements, adding stuff,
>> removing stuff, like that? Possibly there's a code smell here.
>
>
> All the time?

No, or I wouldn't have qualified it with the very weak "possibly".

> For example when creating a set of empty functions to be populated later, or
> empty branches of if and so on to be filled in as so you go.

Forget 'pass' - just give each function a docstring. That
syntactically defines the block, and it's useful.

> Or, for debugging or other reasons, when you need to comment out the
> contents of a block. Then pass needs to be added.

How often do you comment out an entire block and not its header? I
don't remember the last time I did that. It's certainly not so common
that adding 'pass' takes up a significant part of a debugging session.

ChrisA

Steven D'Aprano

unread,
Jul 23, 2016, 11:55:43 AM7/23/16
to
On Sun, 24 Jul 2016 12:06 am, BartC wrote:

> pass can only do so much. If doesn't help here:
>
> for x in sequence:
> print("Something")
> print("Something else")
>
> Was the second print meant to be indented as well or not?

True. But once you start wondering about code the programmer *hasn't*
written, you could drive yourself crazy:

...but what if the second print is supposed to follow
an "if" clause, which has been left out...?

*Most* for-loops have non-empty blocks. Only a tiny minority have empty
blocks for any appreciable period of time. (This is not 1970, and we don't
write timing loops like "for x in range(1000): pass".)

*Most* code is correctly indented. So the interpreter should assume that
indentation *is correct*, unless there is a reason to doubt that. What sort
of reasons could there be?

- if the indentation increases when it shouldn't:

print("Hello")
print("World!") # unexpected indent

- if it dedents to a value that doesn't align with a previous block:

for x in sequence:
print(x)
print("dedented") # half-way between current and previous block

- if it doesn't indent when you expect it to:

for x in sequence:
print(x)


Yes, that last one *could* be an empty block. But empty blocks are rare. Its
more likely to be an error. If it's not an error, than the programmer can
just insert a "pass" statement to satisfy the interpreter.


> Perhaps rather than 'pass', the language ought to have provided an
> optional 'end' keyword to mark the end of a block. Then there would be
> less speculation about what was meant:

It can't be optional. If it were optional, we'd be no better off:

for x in sequence:
print(x)

The "end" is missing, but is it missing from the end of the empty block, or
the end of the non-empty block?

for x in sequence:
end
print(x)

for x in sequence:
print(x)
end


In any case, using "end" instead of "pass" is a poor tradeoff. Instead of
needing to use "pass" (say) one time in a thousand when it is needed, you
would need to use "end" 999 times in a thousand when it *isn't* needed.


> for x in sequence:
> print("Something")
> end
> print("Something else")
>
> (And no speculation at all if 'end' was mandatory. Python already
> provides 'else' (and 'except'?) which can do a similar job in some
> circumstances.)





--

Ben Bacarisse

unread,
Jul 24, 2016, 6:15:40 AM7/24/16
to
Rustom Mody <rusto...@gmail.com> writes:
<snip>
> For a long time the re → dfa transformation went and was taught the laborious
> route:
> re → nfa-with-ε-transitions → nfa-without-ε-transitions → dfa
>
> https://en.wikipedia.org/wiki/Thompson's_construction
> https://en.wikipedia.org/wiki/Powerset_construction
>
> Now there is a direct, straightforward method which only becomes available
> (thinkable) when we have a null regular expression:
> https://drona.csa.iisc.ernet.in/~deepakd/fmcs-06/seminars/presentation.pdf

"Now" seems an odd thing to say since the technique is quite old. It
would be better to say that it has been re-discovered.

But thanks for the link -- I was unaware of the idea. Unfortunately the
material is not well presented there (lower-case phi for the empty set?)
but in trying to understand what it was saying I found:

https://www.cl.cam.ac.uk/~so294/documents/jfp09.pdf

which, in my opinion, does it very much better.

<snip>
--
Ben.

BartC

unread,
Jul 24, 2016, 6:36:00 AM7/24/16
to
On 23/07/2016 16:55, Steven D'Aprano wrote:
> On Sun, 24 Jul 2016 12:06 am, BartC wrote:
>
>> pass can only do so much. If doesn't help here:
>>
>> for x in sequence:
>> print("Something")
>> print("Something else")
>>
>> Was the second print meant to be indented as well or not?
>
> True. But once you start wondering about code the programmer *hasn't*
> written, you could drive yourself crazy:
>
> ...but what if the second print is supposed to follow
> an "if" clause, which has been left out...?

I didn't want to get into this subject again, but Python's indentation
scheme is fragile.

Given an otherwise correctly typed program that compiles with no errors,
then it is very easy (if Backspace or Delete is inadvertently pressed
for example), for an indent to disappear without your noticing, but a
program still compiles. And still runs without execution errors. But
might now be subtly wrong.

Deleting any other character than a leading space or tab I think is more
likely to result in an error that would be noticed, generate a compile
error, or execute error ('variable not initialised'), or that goes wrong
more obviously.

>> Perhaps rather than 'pass', the language ought to have provided an
>> optional 'end' keyword to mark the end of a block. Then there would be
>> less speculation about what was meant:
>
> It can't be optional. If it were optional, we'd be no better off:
>
> for x in sequence:
> print(x)

But that's a choice. Being optional, it means someone /can/ make use of
it...

> The "end" is missing, but is it missing from the end of the empty block, or
> the end of the non-empty block?
>
> for x in sequence:
> end
> print(x)
>
> for x in sequence:
> print(x)
> end

...then it might look like the first example above. The second would be
an error.

>
> In any case, using "end" instead of "pass" is a poor tradeoff. Instead of
> needing to use "pass" (say) one time in a thousand when it is needed, you
> would need to use "end" 999 times in a thousand when it *isn't* needed.

Yes, well, some of us wouldn't mind! But my suggestion is simply that
you can write:

for x in sequence:
end

instead of:

for x in sequence:
pass

The first now allows statements to be added or removed from the body of
the loop without needing to change the 'end'; it wouldn't look out of
place as a trailing 'pass' would.

But thinking about it some more, it wouldn't work. All the blocks that
don't now use 'end' would look odd. I think it would either have to be
all or nothing. I guess nothing.

--
Bartc

BartC

unread,
Jul 24, 2016, 6:45:35 AM7/24/16
to
On 24/07/2016 11:35, BartC wrote:
> On 23/07/2016 16:55, Steven D'Aprano wrote:

>> In any case, using "end" instead of "pass" is a poor tradeoff. Instead of
>> needing to use "pass" (say) one time in a thousand when it is needed, you
>> would need to use "end" 999 times in a thousand when it *isn't* needed.
>
> Yes, well, some of us wouldn't mind!

'end' to terminate a block can be emulated of course:

end=0

def fn(a):
if a<=1:
return 1
else:
return fn(a-1)
end
end

And in this example it wouldn't impact on performance as it is not
evaluated.

But although it can make source code look more conventional, it would
not be supported by the language (repeated, out of place or missing
'end' lines are not an error). And an empty block will still need pass.

--
bartc

Chris Angelico

unread,
Jul 24, 2016, 7:27:36 AM7/24/16
to
On Sun, Jul 24, 2016 at 8:45 PM, BartC <b...@freeuk.com> wrote:
> 'end' to terminate a block can be emulated of course:
>
> end=0
>
> def fn(a):
> if a<=1:
> return 1
> else:
> return fn(a-1)
> end
> end
>
> And in this example it wouldn't impact on performance as it is not
> evaluated.

Actually, they would be (you'll have a LOAD_GLOBAL followed by
POP_TOP). Much better to use Python's inbuilt hash-braces support,
available via a hash-future directive.

#from __future__ import braces

def fn(a): #{
if a <= 1: #{
return 1
#}
else: #{
return fn(a-1)
#}
#}

ChrisA

Steven D'Aprano

unread,
Jul 24, 2016, 8:17:38 AM7/24/16
to
On Sun, 24 Jul 2016 08:35 pm, BartC wrote:

> I didn't want to get into this subject again, but Python's indentation
> scheme is fragile.

*shrug*

Okay, it's fragile. In 20 (give or take a couple) years of programming in
Python, do you know how many times this fragility has been an *actual*
problem? Why don't you take a guess?


> Given an otherwise correctly typed program that compiles with no errors,
> then it is very easy (if Backspace or Delete is inadvertently pressed
> for example), for an indent to disappear without your noticing,

Not really. It depends on the editor, but typically you need to have your
text insertion point somewhere in the indent.

And when you do accidentally press Delete, what happens? The high-level
structure of the code changes. Typically things will no longer align:

def f():
for x in seq:
do_this()
do_that()
do_more()

which is a SyntaxError. It requires quite the coincidence before you can
accidentally delete an indent and have the code still run. Far more likely
is that accidentally pressing delete will break the code in a way that
can't be detected until runtime:

def f():
for x in seq:
do_this()
d_that()
do_more()

Conclusion: if you're the sort of person who habitually presses the Delete
or Backspace key without paying attention, you're going to have a bad time.

(Do other professions make arguments like this? Do carpenters, say, argue
against nail guns because "well if you accidentally hold a loaded nail gun
to your head, then press the trigger, bad things will happen"? Or is it
just programmers who make a common practice of arguing that the programming
language should protect the user from sheer carelessness?)


> but a
> program still compiles. And still runs without execution errors. But
> might now be subtly wrong.

That's certainly *theoretically* possible, but its really not likely. The
only way it could happen is:

- you have a block with at least two lines;
- your insertion point is in the indent of the last line of the block;
- but not the actual text part;
- your editor is configured to dedent on Delete/Backspace, not just
delete a single space; or you're using tabs to indent;
- and the block isn't followed by another block (e.g. if...else...)



> Deleting any other character than a leading space or tab I think is more
> likely to result in an error that would be noticed, generate a compile
> error, or execute error ('variable not initialised'), or that goes wrong
> more obviously.

pi = 314159 # oops accidentally hit delete


[...]
> But my suggestion is simply that you can write:
>
> for x in sequence:
> end
>
> instead of:
>
> for x in sequence:
> pass
>
> The first now allows statements to be added or removed from the body of
> the loop without needing to change the 'end'; it wouldn't look out of
> place as a trailing 'pass' would.

You know, I suspect that you've probably spent more time talking about the
effort required to delete and insert "pass" than the *actual* effort spent
by a hundred programmers deleting and inserting "pass" in their code.


> But thinking about it some more, it wouldn't work. All the blocks that
> don't now use 'end' would look odd. I think it would either have to be
> all or nothing. I guess nothing.




--

Joel Goldstick

unread,
Jul 24, 2016, 8:29:04 AM7/24/16
to
This thread is beginning to feel like a dog whistle for people who
like braces. I've been python coding since 2009 I think, and I think
I have used pass less than a handful of times. ... and except for sets
and dicts, I can't remember using a {

--
Joel Goldstick
http://joelgoldstick.com/blog
http://cc-baseballstats.info/stats/birthdays

Chris Angelico

unread,
Jul 24, 2016, 8:48:40 AM7/24/16
to
On Sun, Jul 24, 2016 at 10:17 PM, Steven D'Aprano <st...@pearwood.info> wrote:
> (Do other professions make arguments like this? Do carpenters, say, argue
> against nail guns because "well if you accidentally hold a loaded nail gun
> to your head, then press the trigger, bad things will happen"? Or is it
> just programmers who make a common practice of arguing that the programming
> language should protect the user from sheer carelessness?)

What about "if you accidentally drop a loaded nailgun, it will fire
sharp bits of metal at high velocity in all directions"? I'd say the
only difference is that carpentry has been around longer, so they had
all these arguments a long time ago and settled on safe ways of doing
things. Why has (most of) the programming world advanced from naive
text editors to programming editors with syntax highlighting, linters,
and other features? Because we are more efficient when our tools
protect us from mistakes. Did people argue a few decades ago about the
value of syntax highlighting? Personally, I took a long while to get
from "well, it'd be nice, but I won't go to any serious effort for it"
to "it's my normal way of coding, and anything that DOESN'T have it is
for quick tweaks only". Also, why does CPython keep an eye on things
like Coverity? If the core devs are competent, they should be able to
write code that never dereferences null pointers, mismatch
INCREF/DECREF, or any of those other errors - right? But life's better
with protection.

It's a trade-off. How much effort do you want to go to? Duplicate work
in daily operation is a high price to pay, which is why Python doesn't
demand "indentation AND 'end' keywords", but protection does have
value. Maybe the people who are most worried about this can enact a
simple rule: no dedent without a blank line? That can easily be
verified by a script, and it'd protect against most of the given
examples. It's not too much effort (after any reasonable-sized block
you'll probably have a blank anyway, so it's only the tiniest of loops
that would be affected). And no language changes are needed :)

ChrisA

BartC

unread,
Jul 24, 2016, 9:09:40 AM7/24/16
to
On 24/07/2016 11:45, BartC wrote:
> On 24/07/2016 11:35, BartC wrote:

> 'end' to terminate a block can be emulated of course:
>
> end=0
>
> def fn(a):
> if a<=1:
> return 1
> else:
> return fn(a-1)
> end
> end

Actually this is a good example of how tabs can go wrong (and how the
tab system /is/ fragile - sorry but it is).

I almost certainly wrote the above using 4 and 8 spaces for the tabs,
except for the 'return 1' where I must have used an actual tab by
mistake. (And I tested it now by doing just that, and posting in alt.test.)

So the original /looked/ correct in my Thunderbird newsreader before I
posted. But after I posted, that tab somehow got changed to 4 spaces, as
it now looks wrong.

In this instance, the result won't compile. But it's not hard to imagine
a much larger program where that change would go unnoticed, and the
result is still valid code**.

Then anyone copying and pasting the posted code, would have a program
with a bug in it.

Mysteriously however, Chris Angelico's reply which quoted my post,
showed a properly tabbed version! (Unless he fixed it manually.)

(** Where working code has been posted, then Python will have picked up
inconsistencies where tabs and spaces are mixed. However take this code:

def fn():
<tab>if a:
<8 spaces>pass

This looks fine in my editor when <tab> is expanded to 4 spaces:

def fn():
if a:
pass

Python however doesn't like it (Python 2 doesn't anyway), because it
somehow assumes tabs expand to 8 spaces, so that the two indents look
like this to it:

def fn():
if a:
pass

So I can see a lot of problems whenever tabs are expanded differently:

a=1
b=0

if a:
<tab>if b:
<tab><tab>print ("One")
<8 spaces>print ("Two")

In my editor with 4-space tabs, it looks like the code will print
nothing as the two print lines are aligned within the 'if b:' block. But
in Python 2, it will print "Two". Python 3 more wisely reports the
inconsistency.)

--
Bartc


Chris Angelico

unread,
Jul 24, 2016, 9:25:12 AM7/24/16
to
On Sun, Jul 24, 2016 at 11:09 PM, BartC <b...@freeuk.com> wrote:
> Actually this is a good example of how tabs can go wrong (and how the tab
> system /is/ fragile - sorry but it is).
>
> I almost certainly wrote the above using 4 and 8 spaces for the tabs, except
> for the 'return 1' where I must have used an actual tab by mistake. (And I
> tested it now by doing just that, and posting in alt.test.)
>

No, it's an example of how *mixing tabs and spaces* can go wrong. And
in fact will always go wrong unless you legislate the width of a tab.
(Recommendation: A tab is equal to 3.14159 spaces. Now you can't get
confused. Use 6.283 spaces if that's too narrow for you.) So don't mix
tabs and spaces. Ever.

ChrisA

Chris Angelico

unread,
Jul 24, 2016, 9:38:51 AM7/24/16
to
On Sun, Jul 24, 2016 at 11:11 PM, Marco Sulla
<mail.py...@marco.sulla.e4ward.com> wrote:
> On 24 July 2016 at 14:48, Chris Angelico <ros...@gmail.com> wrote:
>> Maybe the people who are most worried about this can enact a
>> simple rule: no dedent without a blank line? That can easily be
>> verified by a script, and it'd protect against most of the given
>> examples. It's not too much effort (after any reasonable-sized block
>> you'll probably have a blank anyway, so it's only the tiniest of loops
>> that would be affected). And no language changes are needed :)
>
> I'm incredibly in favor of such a modification, but maybe this is work
> for a linter.

Sorry if I wasn't clear, but I definitely did mean for this to be the
work of a linter ("verified by a script", and "no language changes are
needed").

> Honestly, I find the "pass" statement very clear and simple. There's
> more misleading problems in Python syntax, like this:
>
> someFunction(
> "param1"
> "param2" # comma missed, there will be only one parameter "param1param2"
> )

That can also be caught by a linter; it can also be caught by a
standard habit of ALWAYS putting trailing commas on anything that gets
wrapped. It's not so common with function calls, but the equivalent
situation with list display is:

colors = [
"red",
"green"
"blue",
"yellow",
"cyan",
"magenta"
]

Same problem with the missed comma, but it's also common enough to put
one after "magenta" too, and it's a great protection. Again, you could
have your linter demand this, if you wanted to (and put the linter
into your pre-commit hook or equivalent), or you could just eyeball it
("nothing at the end of the line? really?").

> and this one too:
>
> class Parent(Base):
> __tablename__ = 'parent'
> id = Column(Integer, primary_key=True)
> children = relationship("Child"), # comma inserted by error.
> children will be a tuple and SQLAlchemy will fail with misleading
> errors

Hmm, that's a bit harder to pin down, but since *none* of the members
will have commas here, I'd be surprised to spot one there. Though part
of the problem here is that SQLAlchemy is such a gigantic package that
its error messages tend to be a bit confusing. But that said, here's
what happened when I tried it:

rosuav@sikorsky:~$ python3
Python 3.6.0a3+ (default:bff31254a0f0, Jul 17 2016, 17:39:49)
[GCC 5.4.0 20160609] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from sqlalchemy.ext.declarative import declarative_base
>>> from sqlalchemy import Column, Integer
>>> from sqlalchemy.orm import relationship
>>> Base = declarative_base()
>>> class Parent(Base):
... __tablename__ = 'parent'
... id = Column(Integer, primary_key=True)
... children = relationship("Child"),
...
/usr/local/lib/python3.6/site-packages/sqlalchemy/ext/declarative/base.py:297:
SAWarning: Ignoring declarative-like tuple value of attribute
children: possibly a copy-and-paste error with a comma left at the end
of the line?
"left at the end of the line?" % k)
>>> Parent
<class '__main__.Parent'>
>>>
rosuav@sikorsky:~$ python3 -m pip freeze|grep -i alchemy
SQLAlchemy==1.0.11

Maybe enabling warnings is all you need, or maybe it depends on the
version of SQLAlchemy. In any case, nice spot, declarative-base!

ChrisA

BartC

unread,
Jul 24, 2016, 10:05:47 AM7/24/16
to
On 24/07/2016 14:24, Chris Angelico wrote:
> On Sun, Jul 24, 2016 at 11:09 PM, BartC <b...@freeuk.com> wrote:
>> Actually this is a good example of how tabs can go wrong (and how the tab
>> system /is/ fragile - sorry but it is).
>>
>> I almost certainly wrote the above using 4 and 8 spaces for the tabs, except
>> for the 'return 1' where I must have used an actual tab by mistake. (And I
>> tested it now by doing just that, and posting in alt.test.)
>>
>
> No, it's an example of how *mixing tabs and spaces* can go wrong. And
> in fact will always go wrong unless you legislate the width of a tab.

That's easy to say. How do you actually ensure that they aren't mixed?
The software may not highlight the difference.

I use 100% tabs in my editor. While in Thunderbird, I have to use 100%
spaces otherwise it will screw up. But what stops me pressing tab out of
habit? The code looks right, I post it, and if it then goes wrong, I
might not notice. Nor would anyone else.

Also, sometimes you want to paste code into Thunderbird that contains
tabs; that can be erratic too.

And very often I want to post other people's code that is full of spaces
(notably from Thunderbird), into mine that is full of tabs. (I have the
same problem with other languages, but there it's largely cosmetic.)

So I still think it's fragile, meaning you have to take a lot of extra care.

--
Bartc

Marco Sulla

unread,
Jul 24, 2016, 10:12:46 AM7/24/16
to
On 24 July 2016 at 14:48, Chris Angelico <ros...@gmail.com> wrote:
> Maybe the people who are most worried about this can enact a
> simple rule: no dedent without a blank line? That can easily be
> verified by a script, and it'd protect against most of the given
> examples. It's not too much effort (after any reasonable-sized block
> you'll probably have a blank anyway, so it's only the tiniest of loops
> that would be affected). And no language changes are needed :)

I'm incredibly in favor of such a modification, but maybe this is work
for a linter.

Honestly, I find the "pass" statement very clear and simple. There's
more misleading problems in Python syntax, like this:

someFunction(
"param1"
"param2" # comma missed, there will be only one parameter "param1param2"
)

Steven D'Aprano

unread,
Jul 24, 2016, 10:32:52 AM7/24/16
to
On Mon, 25 Jul 2016 12:05 am, BartC wrote:

>> No, it's an example of how *mixing tabs and spaces* can go wrong. And
>> in fact will always go wrong unless you legislate the width of a tab.
>
> That's easy to say. How do you actually ensure that they aren't mixed?
> The software may not highlight the difference.

(1) Use a better editor.

(2) Use a linter that checks for dodgy indentation.

(3) Run the "tabnanny" module on your script:

python -m tabnanny myscripy.py

(4) Run Python 2.7 with the -t option to warn about inconsistent
tab usage, or -tt to raise errors.

(5) Or for that matter any version of Python going all the way
back to Python 1.5, if not older. There has been no excuse for
getting bitten by mixed tabs/spaces since at least 1998.

(6) Or upgrade to Python 3, which will automatically enforce the
rule about not mixing tabs and spaces.

BartC

unread,
Jul 24, 2016, 10:44:49 AM7/24/16
to
On 24/07/2016 13:17, Steven D'Aprano wrote:
> On Sun, 24 Jul 2016 08:35 pm, BartC wrote:

>> Given an otherwise correctly typed program that compiles with no errors,
>> then it is very easy (if Backspace or Delete is inadvertently pressed
>> for example), for an indent to disappear without your noticing,
>
> Not really. It depends on the editor, but typically you need to have your
> text insertion point somewhere in the indent.
>
> And when you do accidentally press Delete, what happens? The high-level
> structure of the code changes. Typically things will no longer align:
>
> def f():
> for x in seq:
> do_this()
> do_that()
> do_more()
>
> which is a SyntaxError.

Unless it happened on the do_more() line.

> It requires quite the coincidence before you can
> accidentally delete an indent and have the code still run.

On my editor, if I press the cursor up and down keys, the current column
moves to the left if I pass a blank line and stays there. In Python
code, then the cursor will often end up at the start of an indent.

Far more likely
> is that accidentally pressing delete will break the code in a way that
> can't be detected until runtime:
>
> def f():
> for x in seq:
> do_this()
> d_that()
> do_more()

Yes, I mentioned that; it will cause some exception. But moving
do_more() out of the loop above might not do so.

>
> Conclusion: if you're the sort of person who habitually presses the Delete
> or Backspace key without paying attention, you're going to have a bad time.

It happens in all sorts of ways.

Your attention is diverted, you're doing something on your desk, but you
hit one of the keys by mistake. You might have pressed Delete or you
might not. You look at the screen which has a 5000-line program open,
and you see this (borrowing your example and with the cursor at "_"):

def f():
for x in seq:
do_this()
do_that()
_ do_more()

Did you just unindent do_more(), or is that where it's meant to be? Undo
may or may not help (or it may undo something is needed).

If you see this however:

def f():
for x in seq:
do_this()
_o_that()
do_more()

You can see that o_that() doesn't look like its neighbours, and you can
verify there's no o_that() in scope.

--
Bartc

Rustom Mody

unread,
Jul 24, 2016, 10:50:00 AM7/24/16
to
On Sunday, July 24, 2016 at 3:45:40 PM UTC+5:30, Ben Bacarisse wrote:
> Rustom Mody writes:
> <snip>
> > For a long time the re → dfa transformation went and was taught the laborious
> > route:
> > re → nfa-with-ε-transitions → nfa-without-ε-transitions → dfa
> >
> > https://en.wikipedia.org/wiki/Thompson's_construction
> > https://en.wikipedia.org/wiki/Powerset_construction
> >
> > Now there is a direct, straightforward method which only becomes available
> > (thinkable) when we have a null regular expression:
> > https://drona.csa.iisc.ernet.in/~deepakd/fmcs-06/seminars/presentation.pdf
>
> "Now" seems an odd thing to say since the technique is quite old. It
> would be better to say that it has been re-discovered.

The “Now” was not meant time-ly!
>
> But thanks for the link -- I was unaware of the idea. Unfortunately the
> material is not well presented there (lower-case phi for the empty set?)
> but in trying to understand what it was saying I found:
>
> https://www.cl.cam.ac.uk/~so294/documents/jfp09.pdf
>
> which, in my opinion, does it very much better.


Yeah
I think the one used when I was studying was this one
http://www2.in.tum.de/hp/file?fid=571

Anyway my main point was that getting trivial cases right is damn hard
And eliding the trivial case from a notation — because its too trivial to be useful
is damn stupid

Chris Angelico

unread,
Jul 24, 2016, 10:51:23 AM7/24/16
to
On Mon, Jul 25, 2016 at 12:44 AM, BartC <b...@freeuk.com> wrote:
> Your attention is diverted, you're doing something on your desk, but you hit
> one of the keys by mistake. You might have pressed Delete or you might not.
> You look at the screen which has a 5000-line program open, and you see this
> (borrowing your example and with the cursor at "_"):
>
> def f():
> for x in seq:
> do_this()
> do_that()
> _ do_more()
>
> Did you just unindent do_more(), or is that where it's meant to be? Undo may
> or may not help (or it may undo something is needed).

Undo, redo. See what happened. Easy.

Also, if you're regularly committing to source control, you can always
check the diff. Before you 'git commit', check what 'gitk' shows, or
before 'hg commit', have a glance at 'hg diff'. Make sure what you're
seeing is what you intend to change. Remember, code doesn't just
accidentally change; everything should have purpose, including
(especially) any indent/unindent.

Source control protects you from everything other than multiple
changes since the last commit. So commit often. It'll save you a lot
of time - if not coding time, then debating-on-python-list time. :)

ChrisA

BartC

unread,
Jul 24, 2016, 2:14:24 PM7/24/16
to
OK. I understand that it is not possible to point out any kind of
weakness of a language (any language not just Python!) because the
counter-argument is always going to be about:

Use syntax highlighting, use a smart editor, use a version control
system, use a linter, use 'tabnanny', use tool X, Y or Z to get around
the problems, use obscure language options..

The thing is, if everyone does depend more on such tools, then it really
doesn't matter exactly what the language does - the tools will take care
of such details. So the language could delimit blocks using any scheme
it likes, including use 'end', 'else' and so on.

It only becomes important to people like me who use plain editors.

--
Bartc

--
Bartc

nec...@gmail.com

unread,
Jul 24, 2016, 2:27:33 PM7/24/16
to
Don't use tabs. Ever. It's simple.

Jonathan Hayward

unread,
Jul 24, 2016, 2:34:54 PM7/24/16
to
I might point out something that captures something about pass: it is made
to do extra duty in web2py, which is meant to shield students from some of
the more preventable complexities of a LUM CLI, and you don't easily indent
code the way that Vim and Emacs, let alone a full IDE besides the IDE
nature of web2py, forces people to deal with. People getting up to speed
with Vim or Emacs, for anything that is usually indented, find and/or seek
out how to maintain indentation without hitting the space bar 4/8/12/...
times at the beginning of the next line.

And it works. It was probably not intended or even anticipated in the
design of Python, but my understanding is that the adapted usage works well.

And if I may put on asbestos longjohns, there is no reason I am aware of
why syntactic sugar, in the style of Python-influenced Coffeescript, could
not be modified to make "from __future__ import braces" represent a live
and active feature. The net effect of significant whitespace in Python is
that it provides one model to "say what you mean and mean what you say",
and everybody who understands the language recognizes the beginning and end
of a block, the end of a statement, a noop, etc. And this is pretty much
the job description of C-family language syntax etc. Now there are
advantages, namely no braces and no brace holy wars either, fewer Perlish
sigils as even a statement is usually ended by line break, and so on. But
Python-style and C-style syntax alike provide an unambiguous tool to
specify what you want, and an unambiguous means of interpreting what was
actually said. The non-C-style syntax was the biggest "steaming pile of
dinosaur dung" hurdle before ESR appreciated the language, but Python
syntax and C-style syntax are both adequate. They may or may not be equal,
but every instance of code which unambiguous Pythonic syntax is underscored
is an effect that should usually be equally easy to implement with C-style
syntax.
> --
> https://mail.python.org/mailman/listinfo/python-list
>



--
[image: Christos Jonathan Seth Hayward] <https://cjshayward.com/>
*Jonathan Hayward*, a User Experience professional.

Email <cj...@cjshayward.com> • Flagship <https://cjshayward.com/>Website
<https://cjshayward.com/> • Github
<https://github.com/jonathanhayward> • *LinkedIn
<http://www.linkedin.com/in/jonathanhayward>* • Portfolio + More
<http://jonathanhayward.com/> • *Recent Title
<https://www.packtpub.com/application-development/reactive-programming-javascript>*
• Skills <http://jsh.name/>

Loads of talent and a thorough grounding in all major academic disciplines
supporting User Experience.

alister

unread,
Jul 24, 2016, 2:52:16 PM7/24/16
to
whichever language you use regardless of editor, there will have been
design decisions made that could (by your logic) be considered flaws
because an error made is not picked up by the compiler.

apple were recently bitten by "Goto Fail" an error that could not have
happened in the same way with pythons indentation rules.
correct the design of your compiler for one type of error & you will find
that you are now open to another.

IMHO typing pass to signify a deliberately empty block is a minor nuisance
(at worst) making it optional is more likely to lead to bugs

either way my opinion is nut important because the decision has already
been made.



--
I sat laughing snidely into my notebook until they showed me a PC running
Linux... And oh! It was as though the heavens opened and God handed down a
client-side OS so beautiful, so graceful, and so elegant that a million
Microsoft developers couldn't have invented it even if they had a hundred
years and a thousand crates of Jolt cola.

-- Polly Sprenger, LAN Times

Chris Angelico

unread,
Jul 24, 2016, 3:00:49 PM7/24/16
to
On Mon, Jul 25, 2016 at 4:14 AM, BartC <b...@freeuk.com> wrote:
> OK. I understand that it is not possible to point out any kind of weakness
> of a language (any language not just Python!) because the counter-argument
> is always going to be about:
>
> Use syntax highlighting, use a smart editor, use a version control system,
> use a linter, use 'tabnanny', use tool X, Y or Z to get around the problems,
> use obscure language options..

Obscure? I guess - it's not like it's listed in the --help screen. Oh
wait. And of course, all you need to do is upgrade to Python 3 and it
becomes the default.

Wait, you lump "use a VCS" into the category of "stuff people tell you
that you're not really willing to do"? Are you saying you don't use
git, Mercurial, etc, etc, to track your projects? Then start using
one. Now. "Now-now", as Princess Anna says in the Italian dub.

> The thing is, if everyone does depend more on such tools, then it really
> doesn't matter exactly what the language does - the tools will take care of
> such details. So the language could delimit blocks using any scheme it
> likes, including use 'end', 'else' and so on.
>
> It only becomes important to people like me who use plain editors.

Yes, that's exactly right. Tell me, is this part of a linter or a
language compiler/interpreter?

rosuav@sikorsky:~$ cat 1.c
#include <stdio.h>
int main()
{
int months[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
printf("The array is at %p.\n", months);
printf("There are %d days in December.\n", months[12]);
printf("And this is what 28 looks like: %s\n", months[1]);
}

rosuav@sikorsky:~$ gcc -Wall -O2 1.c
1.c: In function ‘main’:
1.c:7:9: warning: format ‘%s’ expects argument of type ‘char *’, but
argument 2 has type ‘int’ [-Wformat=]
printf("And this is what 28 looks like: %s\n", months[1]);
^
1.c:6:2: warning: array subscript is above array bounds [-Warray-bounds]
printf("There are %d days in December.\n", months[12]);
^
rosuav@sikorsky:~$


Today's C compilers emit warnings for things that yesterday's
third-party linters did. Is there virtue in running gcc with all
warnings disabled? Equally, is there a valid reason for choosing to
use a "plain editor" when you could use one that helps you?

A skilled craftsman in any field will choose to use quality tools.
They save time, and time is money. Are there any carpenters who
restrict themselves to hand tools? (Stylistic choice aside.
KirkwoodWorking has "hand tools Sunday" where he avoids all power
tools, and it's taking him months and months to finish one cabinet.
But the rest of the week, power tools win.) Would you, if given the
choice, use an ancient 80386 running MS-DOS in 4MB of RAM, or a modern
system running a modern OS in 16GB? Would you type your code on a
tablet computer or something with a real keyboard? So why do you use
"dumb editor" as a line of argument, rather than getting a smarter
editor?

I don't have a lot of sympathy for people who use suboptimal tools and
expect everything to work for them. Sure, sometimes you're forced to
use something less than ideal (maybe you're stuck on someone else's
Windows box and good tools simply aren't there, and you can't go
installing a ton of stuff just to get started), but then you KNOW
you're working in bad conditions. You don't make that your normal
life.

ChrisA

BartC

unread,
Jul 24, 2016, 4:03:48 PM7/24/16
to
On 24/07/2016 20:00, Chris Angelico wrote:
> On Mon, Jul 25, 2016 at 4:14 AM, BartC <b...@freeuk.com> wrote:

> A skilled craftsman in any field will choose to use quality tools.

Materials (ie. languages) are important too.

> So why do you use
> "dumb editor" as a line of argument, rather than getting a smarter
> editor?

Perhaps because I prefer to use my own languages and I don't have anyone
writing the specialist tools for me that would be necessary.

> I don't have a lot of sympathy for people who use suboptimal tools and
> expect everything to work for them. Sure, sometimes you're forced to
> use something less than ideal (maybe you're stuck on someone else's
> Windows box and good tools simply aren't there, and you can't go
> installing a ton of stuff just to get started), but then you KNOW
> you're working in bad conditions. You don't make that your normal
> life.

Some of us are used to working with minimalist tools and can be
extremely productive with them.

But since you used some C, let me give an example of poor design from
that language (there are plenty; I've written up quite a big collection
of them).

You might know that type declarations in C, as soon as you go beyond the
basics, become completely impossible and convoluted. I've never managed
to get my head around them.

There are utilities such as 'Cdecl' that are used to convert a C
declaration to English, and vice versa. That's how good a feature they are!

So what would have been a better solution here: to have fixed the
language, or to have grafted on a simpler type declaration scheme that
could co-exist with the old one; or to have ignored the problem and
depended on using external tools?

Or just insisted that everyone learns that arcane aspect of C, despite
it being unreadable and error-prone.

(My own solution is that I use a home-made language in place of C, which
has fixed most such problems. So my main 'tool' is a custom-made language.

And for block delimiting, it uses neither tabbed indents or braces!)

--
Bartc

Chris Angelico

unread,
Jul 24, 2016, 5:09:02 PM7/24/16
to
On Mon, Jul 25, 2016 at 6:03 AM, BartC <b...@freeuk.com> wrote:
> On 24/07/2016 20:00, Chris Angelico wrote:
>>
>> On Mon, Jul 25, 2016 at 4:14 AM, BartC <b...@freeuk.com> wrote:
>
>
>> A skilled craftsman in any field will choose to use quality tools.
>
> Materials (ie. languages) are important too.

Materials, tools, same difference. (Not sure I could even draw the
line in software, and ultimately, my line of argument applies equally
to both.)

>> So why do you use
>> "dumb editor" as a line of argument, rather than getting a smarter
>> editor?
>
>
> Perhaps because I prefer to use my own languages and I don't have anyone
> writing the specialist tools for me that would be necessary.

So because you've chosen to use your own languages, you are frustrated
at Python because you're not using a decent editor? Get yourself
something nice and configurable, so that when you open a Python file
it gives you the features you need. I use SciTE, and it quite happily
is currently working with text, Pike, Pike Module, reStructuredText,
HTML, SRT, and Python files, and that's counting only the ones that I
have loaded in it right at this instant. Had some C files up recently
(both .c and .h - was editing CPython), and various other things.
SciTE doesn't recognize .srt files, so it treats them as plain text -
as in, like a dumb editor would. Even if your own language can't be
parsed using any existing parser (adding language support usually
isn't that hard, if the same parser can be reused), you can still make
use of smart editor features for all other languages you work with.
Why is this such a problem? Why is it so hard?

>> I don't have a lot of sympathy for people who use suboptimal tools and
>> expect everything to work for them. Sure, sometimes you're forced to
>> use something less than ideal (maybe you're stuck on someone else's
>> Windows box and good tools simply aren't there, and you can't go
>> installing a ton of stuff just to get started), but then you KNOW
>> you're working in bad conditions. You don't make that your normal
>> life.
>
> Some of us are used to working with minimalist tools and can be extremely
> productive with them.

And then you complain that the language is "fragile" or in some way
frustrating to you. Because you've restricted yourself to minimalist
tools. Go ahead! Be productive. I'm sure there are people out there
saying "I'm used to working with C and can be extremely productive
with it". Let 'em. Me, I'll use high level languages and be even more
productive. Thanks.

> But since you used some C, let me give an example of poor design from that
> language (there are plenty; I've written up quite a big collection of them).
>
> You might know that type declarations in C, as soon as you go beyond the
> basics, become completely impossible and convoluted. I've never managed to
> get my head around them.
>
> There are utilities such as 'Cdecl' that are used to convert a C declaration
> to English, and vice versa. That's how good a feature they are!
>
> So what would have been a better solution here: to have fixed the language,
> or to have grafted on a simpler type declaration scheme that could co-exist
> with the old one; or to have ignored the problem and depended on using
> external tools?
>
> Or just insisted that everyone learns that arcane aspect of C, despite it
> being unreadable and error-prone.

When do you get those uber-convoluted declarations in C? Sure, they
come up in C++ (which is why the language grew some features to manage
that complexity), but outside of demonstration code, when do you get
actual declarations of massively-nested constructs? I've literally
*never* seen them - not rarely, NEVER - in production code.

> (My own solution is that I use a home-made language in place of C, which has
> fixed most such problems. So my main 'tool' is a custom-made language.
>
> And for block delimiting, it uses neither tabbed indents or braces!)

Sure. You're most welcome to use that. But it doesn't mean that Python
is unusable.

Plus, I'd much rather trust Python in production than something
custom-made, even by me. The performance, reliability, and security of
a well-respected language far outstrip anything I could build.

ChrisA

BartC

unread,
Jul 24, 2016, 6:13:46 PM7/24/16
to
On 24/07/2016 22:08, Chris Angelico wrote:
> On Mon, Jul 25, 2016 at 6:03 AM, BartC <b...@freeuk.com> wrote:

>> Perhaps because I prefer to use my own languages and I don't have anyone
>> writing the specialist tools for me that would be necessary.
>
> So because you've chosen to use your own languages, you are frustrated
> at Python because you're not using a decent editor?

My point is that with a bit more thought into the design of a language,
clever tools would be less important. A language should stand by itself
and not lean on specialist tools to be make it more usable.

A solid end-of-block symbol (as you get with 'else' and 'except' because
then you KNOW that's the end of that block) would have been welcome with
the Python indent scheme.

> Get yourself
> something nice and configurable, so that when you open a Python file
> it gives you the features you need. I use SciTE,

I have one big problem with most editors (including SciTE): they are not
properly line-oriented. If you hold down Backspace in the middle of a
line, it won't just delete until it hits the beginning of the line; it
keeps going! I can't live with that: editing would be like walking on
eggshells. I need hard line stops. (I can't touch type; I need to look
at the keyboard a lot.)

(And SciTE won't support a custom language for highlighting and stuff.
Maybe it's configurable, but there seems to be a lexer module that needs
to be provided. Suddenly it seems a lot of work to do.)

> Why is this such a problem? Why is it so hard?

Who says it's a problem? I'm quite happy with the screen editors I use
that are little changed since the early 80s (and before that I used line
editors; now those /were/ horrible).

>> You might know that type declarations in C, as soon as you go beyond the
>> basics, become completely impossible and convoluted.

> When do you get those uber-convoluted declarations in C?

(They don't need to be elaborate to start being confusing. Take 'int
*a[]' and 'int (*a)[]'; one of these is an array of pointers, the other
a pointer to an array. Quite different! But which is which?

And when you start dealing with pointers to functions, now you're
talking! And yes C++ takes this to a whole new dimension. What a
language...)

>> And for block delimiting, it uses neither tabbed indents or braces!)
>
> Sure. You're most welcome to use that. But it doesn't mean that Python
> is unusable.

It's not unusable. Just a minor nuisance (working with Python using my
editor). And troublesome pasting Python code from elsewhere which is
always full of spaces rather than tabs. (Sometimes uneven mixes of
spaces too.)

The Python indent thing isn't a big deal. But having 'end' after each
(final) block would have made life just a bit simpler.

The whole topic is a trivial point of syntax. (My only issue with 'pass'
is that, for some inexplicable reason, my fingers always type it is
'#pass'.)

> Plus, I'd much rather trust Python in production than something
> custom-made, even by me. The performance, reliability, and security of
> a well-respected language far outstrip anything I could build.

Well, performance is where I usually have an edge at the minute (with my
own interpreted language). But if I had to recommend a language, it
would have to be Python (I can't be dealing with users and support and
all that...)

--
Bartc

Gregory Ewing

unread,
Jul 24, 2016, 8:40:19 PM7/24/16
to
BartC wrote:
> On 24/07/2016 14:24, Chris Angelico wrote:
>
>> No, it's an example of how *mixing tabs and spaces* can go wrong. And
>> in fact will always go wrong unless you legislate the width of a tab.
>
> That's easy to say. How do you actually ensure that they aren't mixed?
> The software may not highlight the difference.

Python 3 will tell you immediately, since it forbids
mixing tabs and spaces.

>>> def f():
... a
... b
File "<stdin>", line 3
b
^
TabError: inconsistent use of tabs and spaces in indentation

> So I still think it's fragile, meaning you have to take a lot of extra
> care.

The practical experience of a very large number of Python
programmers suggests that it requires very little additional
care over and above that normally required for programming.

What's your experience? How often has this caused you trouble,
and what proportion is it of all the Python programming you've
done?

--
Greg

Rustom Mody

unread,
Jul 24, 2016, 8:57:18 PM7/24/16
to
On Monday, July 25, 2016 at 1:33:48 AM UTC+5:30, BartC wrote:
> On 24/07/2016 20:00, Chris Angelico wrote:
> > On Mon, Jul 25, 2016 at 4:14 AM, BartC wrote:
>
> > A skilled craftsman in any field will choose to use quality tools.
>
> Materials (ie. languages) are important too.
>
> > So why do you use
> > "dumb editor" as a line of argument, rather than getting a smarter
> > editor?
>
> Perhaps because I prefer to use my own languages and I don't have anyone
> writing the specialist tools for me that would be necessary.

This language-vs-IDE divide has been recogized:
http://blog.osteele.com/posts/2004/11/ides/

Gregory Ewing

unread,
Jul 24, 2016, 9:04:58 PM7/24/16
to
BartC wrote:
> (They don't need to be elaborate to start being confusing. Take 'int
> *a[]' and 'int (*a)[]'; one of these is an array of pointers, the other
> a pointer to an array. Quite different! But which is which?

Where have you seen 'int (*a)[]' used? I don't think I've
ever seen any real-life C code that used a pointer to an
array, as opposed to a pointer to the first element of the
array. Usually it would just be declared either 'int a[]'
or 'int *a'.

--
Greg

BartC

unread,
Jul 24, 2016, 9:14:58 PM7/24/16
to
On 25/07/2016 01:40, Gregory Ewing wrote:
> BartC wrote:

>> So I still think it's fragile, meaning you have to take a lot of extra
>> care.
>
> The practical experience of a very large number of Python
> programmers suggests that it requires very little additional
> care over and above that normally required for programming.
>
> What's your experience? How often has this caused you trouble,
> and what proportion is it of all the Python programming you've
> done?
>

I've done little Python coding but still, having to use kid gloves for
indents does figure quite a bit in that.

I can give some more examples but I'll probably be told that I'm using
the wrong tools! Which suggest there is a problem, but the effort has
gone into working around them using external tools. (But understandable
if the language design was fixed 25 years ago.)

For example:

if cond:
a
b

I want to comment out the if statement temporarily, but I also have to
fix the indents:

#if cond:
a
b

(Or add the comment and insert a dummy 'if 1:'.)

Or I want to add a temporary condition around:

a
b

which again requires me to indent those statements (and unindent them
again later). Or I want to permanently have a commented out #if guard
around some code:

#if cond:
a
b

to be uncommented from time to time (to do with debugging). But it's not
as simple as just uncommenting that one line.

Or I want to have a temporary print statement within a block, but it
needs to be at the right indentation. Not a great imposition, but it's
now less visible as a temporary addition.

Or I need to move or copy code from one location to another, but the
indentation levels are different. This would need fixing in other
languages too, but if this is part of a temporary try out which will
change again a few minutes later, I can dispense with the correct
indentation in another language, until the code is more permanent.

In short, because correct indentation is required at all times, it's
less flexible when you want to do a lot of messing around.

Now, if I was going to do a LOT of Python coding, then I would solve
most of those problems (by having my own tool to superimpose a more
amenable syntax on the language). For casual work though I have to go
along with the indent scheme. (And there are usually other issues with
Python that are more troublesome than getting the layout right.)

I'll leave you with a code fragment that might be pasted from elsewhere
(it's not meant to mean anything):

if cond:
a
b
c

The question is: is this the whole block? We don't know, as we can't see
what came next. But if now I add the next line, and it was this
(anything actually with one less indent):

if cond2:

then yes it was the whole block, IF we assume an indent didn't get
clobbered in the process! But if the line happened to be:

else:

now we know for sure.


--
Bartc

Ben Finney

unread,
Jul 24, 2016, 9:45:36 PM7/24/16
to
BartC <b...@freeuk.com> writes:

> On 25/07/2016 01:40, Gregory Ewing wrote:
> > What's your experience? How often has this caused you trouble, and
> > what proportion is it of all the Python programming you've done?
>
> I've done little Python coding

Then you are not in a position to make the prnouncements about Python's
effect on coding efficiency that you are pronouncing, in this and other
threads.

> I can give some more examples but I'll probably be told that I'm using
> the wrong tools!

You should gain a lot more experience using Python for productive work,
before declaring any effects on productive work inherent to the language
design.

> Which suggest there is a problem

Or that the programming tools of 25 years ago compare poorly to today's
tools.

Even tools that have existed for 25 years have benefited from the
intervening time. No-one uses Emacs *as it was 25 years ago* and expects
to be as proficient as someone using Emacs as it is today.

--
\ “Beware of bugs in the above code; I have only proved it |
`\ correct, not tried it.” —Donald Knuth, 1977-03-29 |
_o__) |
Ben Finney

Steven D'Aprano

unread,
Jul 24, 2016, 10:37:36 PM7/24/16
to
On Mon, 25 Jul 2016 08:13 am, BartC wrote:

> A solid end-of-block symbol (as you get with 'else' and 'except' because
> then you KNOW that's the end of that block) would have been welcome with
> the Python indent scheme.

A solid end-of-block symbol would have been entire redundant and
unnecessary. You know when the block ends: it ends when one of two things
happen:

- you dedent out a level;
- you reach the end of file;

whichever happens next. Requiring an otherwise pointless end of block
delimiter to protect against your cat walking over your keyboard, or clumsy
programmers who accidentally hit keys and don't notice, is not a virtue. It
doesn't make the language better. It just increases friction when writing
code.

There are approximately a million billion trillion zillion things that can
go wrong if you randomly hit keys without paying attention to what you are
doing, and regardless of whether you have a static or dynamic language,
only a tiny fraction of them can be detected ahead of time.

When you're typing plain English paragraphs like this, why don't you end
each sentence with "END", just in case you accidentally delete the
punctuation mark and don't notice? END That way, you have less fragile
text. END The reader can easily tell when you have the end of a sentence,
even if you accidentally delete the full stop, because of the special end
marker. END And two end markers could represent the end of a paragraph,
just in case you accidentally delete the break between paragraphs? END END

Actually, COMMA now that I think about it, COMMA I'm starting to come around
to your way of thinking. END We can tag other punctuation marks too, COMMA
like commas, COMMA to ensure that our language is less fragile. END No more
will you have to fear the ambiguity of accidentally dropping a comma: COLON
END END

"We invited the strippers, JFK, and Stalin."
"We invited the strippers, JFK and Stalin."

http://i.imgur.com/fycHx.jpg


Instead, COMNA the error becomes obvious: COLON EMD END

" QUOTE We invited the strippers, COMMA JFK COMMA and Stalin. END " QUOTE
END END





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

Michael Torrie

unread,
Jul 24, 2016, 10:55:00 PM7/24/16
to
On 07/24/2016 07:14 PM, BartC wrote:
> I've done little Python coding but still, having to use kid gloves for
> indents does figure quite a bit in that.
>
> I can give some more examples but I'll probably be told that I'm using
> the wrong tools! Which suggest there is a problem, but the effort has
> gone into working around them using external tools. (But understandable
> if the language design was fixed 25 years ago.)

I only code in Python these days and I simply do not find the indenting
syntax to be a problem.

Far more often I'm bitten by the dynamic nature of Python (would happen
in any dynamic language). I'll be using a particular member attribute
which I accidentally misspell somewhere and sometimes that results in
silent failure. Something doesn't work, but no exception is thrown.
Unit tests, and perhaps lint, are required to catch these errors. That
is one thing about a dynamic language: comprehensive testing is required
as you go along.

>
> For example:
>
> if cond:
> a
> b
>
> I want to comment out the if statement temporarily, but I also have to
> fix the indents:
>
> #if cond:
> a
> b

Good example, and I've encountered this one, but honestly fixing the
indent is best programming practice anyway. If I want to preserve
context, copying the entire block and then commenting it out to preserve
it is what I prefer. Anyway, I'd want to fix indenting even if I was
using braces. Just to make the code readable and maintainable over time
as more often than not temporary becomes permanent. If it's truly a
temporary removal, your "if 1:" idiom seems most correct to me, with the
original condition commented out.

Also there are times when I simply don't worry about commenting things
out. I just delete them and fix the indenting and move on with life. I
can always revert my changes if I end up barking up the wrong tree.

>
> (Or add the comment and insert a dummy 'if 1:'.)

This is a good idea for temporarily taking out the condition. Sounds
like good practice to me.


>
> Or I want to add a temporary condition around:
>
> a
> b
>
> which again requires me to indent those statements (and unindent them
> again later). Or I want to permanently have a commented out #if guard
> around some code:
>
> #if cond:
> a
> b
>
> to be uncommented from time to time (to do with debugging). But it's not
> as simple as just uncommenting that one line.

With a end statement you'd of course have to comment out both the if and
the end lines. Just to nitpick.

>
> Or I want to have a temporary print statement within a block, but it
> needs to be at the right indentation. Not a great imposition, but it's
> now less visible as a temporary addition.

Pretty much all print statements in my code are visible as a temporary
addition. There is really little other reason to use it. So every so
often I'll search for all my print statements and comment them out or
delete them once the code is operational. But even then, using a
logging function is probably even better solution.

> Or I need to move or copy code from one location to another, but the
> indentation levels are different. This would need fixing in other
> languages too, but if this is part of a temporary try out which will
> change again a few minutes later, I can dispense with the correct
> indentation in another language, until the code is more permanent.

In venerable old ViM I just highlight the block and move it in or out.
Not having editor support would make this very painful. But you'd be
wanting to adjust the indenting anyway, in any language. So while it
would cause an error in Python, in any other language you'd want to do
this anyway, just to make the code readable.

> In short, because correct indentation is required at all times, it's
> less flexible when you want to do a lot of messing around.

I guess I just don't find this to be particularly problematic. And
Python is great for doing a lot of messing around in for me.

> Now, if I was going to do a LOT of Python coding, then I would solve
> most of those problems (by having my own tool to superimpose a more
> amenable syntax on the language). For casual work though I have to go
> along with the indent scheme. (And there are usually other issues with
> Python that are more troublesome than getting the layout right.)

I tend to not have a lot of strong opinions about languages I have
little experience in. What is it about your experience that leads to
such strong opinions about a language you do very little in? I dislike
what I see of Ruby but I have no opinions strong enough to voice on the
Ruby lists (or even read them). Just curious.

> I'll leave you with a code fragment that might be pasted from elsewhere
> (it's not meant to mean anything):
>
> if cond:
> a
> b
> c
>
> The question is: is this the whole block? We don't know, as we can't see
> what came next. But if now I add the next line, and it was this
> (anything actually with one less indent):
>
> if cond2:
>
> then yes it was the whole block, IF we assume an indent didn't get
> clobbered in the process! But if the line happened to be:
>
> else:
>
> now we know for sure.

I've never had this problem in Python. I have the source file in front
of me. I can scroll down until the block ends. And if the programmer
keeps his functions short, it's as readable or more readable than in any
other language. I submit you'd have the same readability problem with a
very long and deeply blocked C function without the help of something
like brace matching in your editor. It's true I can reformat the file
to clean up the indenting in a C program, but the author should have
done that to begin with. Just because a C function compiles doesn't
mean it's correct, and if the indenting is all over the place you can't
easily follow the logic and judge its correctness anyway.

Chris Angelico

unread,
Jul 24, 2016, 11:12:21 PM7/24/16
to
On Mon, Jul 25, 2016 at 12:48 PM, Michael Torrie <tor...@gmail.com> wrote:
> Far more often I'm bitten by the dynamic nature of Python (would happen
> in any dynamic language). I'll be using a particular member attribute
> which I accidentally misspell somewhere and sometimes that results in
> silent failure. Something doesn't work, but no exception is thrown.
> Unit tests, and perhaps lint, are required to catch these errors. That
> is one thing about a dynamic language: comprehensive testing is required
> as you go along.
>

To be quite honest, comprehensive testing is needed in more static
languages too. There are certain categories of error which can be
detected by a compiler/linter, and certain which cannot; a language
that forces you to declare variables will catch variable name
misspellings, but only if they don't land you on an existing variable,
and still won't catch the dynamic places like dict keys (imagine
getting a block of JSON from somewhere, converting it into a
dictionary, and looking up stuff in it - the compiler can't know
whether your incoming data is correct and your code wrong, or the
other way around). A language with less dynamism might be able to
catch more, but still not everything, so ultimately, it all comes down
to testing anyway.

ChrisA

Rustom Mody

unread,
Jul 24, 2016, 11:20:28 PM7/24/16
to
On Monday, July 25, 2016 at 8:42:21 AM UTC+5:30, Chris Angelico wrote:
So far — Fine!


> so ultimately, it all comes down to testing anyway.

All??

There is a famous quote by Dijkstra:
«Testing shows the presence, not the absence of bugs»

Or if you prefer things of a more ‘practical’ (so-called_ nature:
http://www.testingexcellence.com/reasons-automated-tests-fail-to-find-regression-bugs/

Chris Angelico

unread,
Jul 24, 2016, 11:29:10 PM7/24/16
to
On Mon, Jul 25, 2016 at 1:20 PM, Rustom Mody <rusto...@gmail.com> wrote:
>> so ultimately, it all comes down to testing anyway.
>
> All??
>
> There is a famous quote by Dijkstra:
> «Testing shows the presence, not the absence of bugs»
>
> Or if you prefer things of a more ‘practical’ (so-called_ nature:
> http://www.testingexcellence.com/reasons-automated-tests-fail-to-find-regression-bugs/

If testing won't find the bugs, what will? By "testing", I don't just
mean automated tests, although of course that's one of the most
efficient ways. Dogfooding is an important part of testing too.

ChrisA

Rustom Mody

unread,
Jul 24, 2016, 11:46:57 PM7/24/16
to
On Monday, July 25, 2016 at 8:59:10 AM UTC+5:30, Chris Angelico wrote:
> On Mon, Jul 25, 2016 at 1:20 PM, Rustom Mody wrote:
> >> so ultimately, it all comes down to testing anyway.
> >
> > All??
> >
> > There is a famous quote by Dijkstra:
> > «Testing shows the presence, not the absence of bugs»
> >
> > Or if you prefer things of a more ‘practical’ (so-called_ nature:
> > http://www.testingexcellence.com/reasons-automated-tests-fail-to-find-regression-bugs/
>
> If testing won't find the bugs, what will? By "testing", I don't just
> mean automated tests, although of course that's one of the most
> efficient ways. Dogfooding is an important part of testing too.

Dijkstra made that (and such) statements towards advocating formal program
proving.

Whether we agree/disagree with that line is one thing.
The bald fact that tests are finite and the actual search space for cases for
anything remotely non-trivial is infinite is undeniable.

Steven D'Aprano

unread,
Jul 25, 2016, 12:27:26 AM7/25/16
to
On Mon, 25 Jul 2016 01:20 pm, Rustom Mody wrote:

>> so ultimately, it all comes down to testing anyway.
>
> All??

Ultimately, yes. It all comes down to testing. How else do you know that
your program to flernge the widget *actually* flernges the widget or not?


> There is a famous quote by Dijkstra:
> «Testing shows the presence, not the absence of bugs»

Correct. And as Knuth said:

"Beware of bugs in the above code; I have only proved it correct, not tried
it."

You cannot *prove* the absence of bugs in a large, complex program, because
how do you know your proof is correct? Your automatic prover is a program,
which will contain bugs. If you don't use an automatic prover, then how do
you know you didn't make a mistake in your manual proof?

Ultimately, any program beyond a certain level of complexity can only be
*suspected* to be correct.

> Or if you prefer things of a more ‘practical’ (so-called_ nature:
>
http://www.testingexcellence.com/reasons-automated-tests-fail-to-find-regression-bugs/





Steven D'Aprano

unread,
Jul 25, 2016, 3:20:36 AM7/25/16
to
On Monday 25 July 2016 13:46, Rustom Mody wrote:

> The bald fact that tests are finite and the actual search space for cases for
> anything remotely non-trivial is infinite is undeniable.

I deny it :-P

"Infinity" is pretty big. It's *really* big. It's bigger than most people
think. You might think your credit card bill last month was big, but infinity
is much bigger.

Mathematicians deal with numbers which are so unfathomably huge that we can't
even talk about them using the ordinary notation we use for ordinary numbers.
Take something as unbelievably big as Graham's Number, so big they had to
invent specialised notation just to discuss it:

http://mathworld.wolfram.com/GrahamsNumber.html

http://www.youtube.com/watch?v=XTeJ64KD5cg

Let's make it bigger! Square it. No, cube it! Take the factorial! Cube it
again! Raise that number to the power of itself! Add one!

Compared to infinity, this new number is infinitesimally tiny. Compared to
infinity, this new number is barely even there. Compared to infinity, that new
number might as well be zero.

Given that any actual program has to *exist* in order to be tested, it must be
finite in size. Since the observable universe contains "merely" something of
the order of 10**89 or so elementary particles (electrons, protons, etc) even
with the combinatory explosion of possibilities, the upper bound on the number
of test cases will be something like (10**89)**(10**89), which is minuscule
compared to Graham's Number, let alone our even Vaster number. Which is so far
short of infinity that in one sense we can say that it has barely even taken a
single step in the direction of infinity.


(Of course I realise you were using "infinite" just as hyperbole. I just
couldn't resist bringing Graham's Number into the discussion.)


--
Steve

BartC

unread,
Jul 25, 2016, 5:45:10 AM7/25/16
to
On 25/07/2016 02:04, Gregory Ewing wrote:
> BartC wrote:
>> (They don't need to be elaborate to start being confusing. Take 'int
>> *a[]' and 'int (*a)[]'; one of these is an array of pointers, the
>> other a pointer to an array. Quite different! But which is which?
>
> Where have you seen 'int (*a)[]' used? I don't think I've
> ever seen any real-life C code that used a pointer to an
> array, as opposed to a pointer to the first element of the
> array.

(Yes everyone uses T*a (pointer to T) instead of T(*a)[] (pointer to
array of T), because, thanks to how C mixes up deferencing and indexing,
the former can be accessed as a[i] instead of (*a)[i].

But it's wrong, and leads to errors that the language can't detect. Such
as when a points to a single element not a block: define ANY combination
such as 'pointer to pointer to array'; you need to access an element
using (deref, deref, index), but C also allows (index, deref, deref) or
(deref, index, deref), or (index, index, index).

Provided the right number of deref/index ops are provided, C can't tell
the difference because derefs and index ops are interchangeable! But
only one combination is correct.

I came across T(*a)[] when translating from a language that handles this
properly, into C. In fact I use the translator to convert type-specs
from straightforward format into C. Another tool to get around a flaw.)

--
Bartc

BartC

unread,
Jul 25, 2016, 6:39:36 AM7/25/16
to
On 25/07/2016 03:37, Steven D'Aprano wrote:
> On Mon, 25 Jul 2016 08:13 am, BartC wrote:
>
>> A solid end-of-block symbol (as you get with 'else' and 'except' because
>> then you KNOW that's the end of that block) would have been welcome with
>> the Python indent scheme.
>
> A solid end-of-block symbol would have been entire redundant and
> unnecessary. You know when the block ends: it ends when one of two things
> happen:
>
> - you dedent out a level;
> - you reach the end of file;

> whichever happens next. Requiring an otherwise pointless end of block
> delimiter to protect against your cat walking over your keyboard, or clumsy
> programmers who accidentally hit keys and don't notice, is not a virtue. It
> doesn't make the language better. It just increases friction when writing
> code.

Remember when movies used to finish with "The End"? I wonder what that
was all about? After all you can tell when it's finished when you see
the opening titles of the next movie! Or when the lights come back up in
the cinema ('theater').

If you've ever watched Monty Python (on topic!) and the Holy Grail at
the cinema, you will have appreciated it even more. You just get a black
screen and nothing more happens. People were waiting for several
minutes, eventually starting to get up and leave.

END may seem redundant, but it's just very handy. You know FOR SURE you
are at a particular point, instead of having to infer it from what may
or may not come next, which might not be visible off the bottom of the
screen.

> When you're typing plain English paragraphs like this, why don't you end
> each sentence with "END"

The period is more the equivalent of C's semicolon. That nearly always
coincides with end-or-line so also lends itself to be inferred, as
horizontally source code tends to be a limited width.

But otherwise free-flowing English text is not a good comparison with a
programming language syntax.

--
Bartc

Random832

unread,
Jul 25, 2016, 10:43:39 AM7/25/16
to
On Sun, Jul 24, 2016, at 18:13, BartC wrote:
> (They don't need to be elaborate to start being confusing. Take 'int
> *a[]' and 'int (*a)[]'; one of these is an array of pointers, the other
> a pointer to an array. Quite different! But which is which?

int (*a)[]; === int x[]; where x is (*a). To work out the other one you
need to know operator precedence, but you need to know operator
precedence to understand a _lot_ of things.

C type _casts_ are slightly harder, since you have to work out where the
identifier belongs in a token sequence that has had it removed. But it's
usually not hard [look for the sequence "*)", which is otherwise illegal
and appears in most complicated type casts].

Rustom Mody

unread,
Jul 25, 2016, 12:55:14 PM7/25/16
to
On Monday, July 25, 2016 at 7:15:36 AM UTC+5:30, Ben Finney wrote:
> Even tools that have existed for 25 years have benefited from the
> intervening time. No-one uses Emacs *as it was 25 years ago* and expects
> to be as proficient as someone using Emacs as it is today.

As a general comment — fine
Your exemplar however is ironic

What everyone calls window it calls frame; what everyone calls pane it calls
window because its legacy from pre-gui days

What everyone calls Alt it calls Meta and shortens it to “M-” because the Sun workstations that have been dead 20 years had a Meta-key

And the most annoying bugbear:

The whole world uses cua keys:
https://en.wikipedia.org/wiki/IBM_Common_User_Access
it proudly sticks to what it was doing pre-cua

I could go on…

Chris Angelico

unread,
Jul 25, 2016, 1:02:45 PM7/25/16
to
On Tue, Jul 26, 2016 at 2:54 AM, Rustom Mody <rusto...@gmail.com> wrote:
> The whole world uses cua keys:
> https://en.wikipedia.org/wiki/IBM_Common_User_Access
> [emacs] proudly sticks to what it was doing pre-cua

Sadly, the "whole world" doesn't. Windows itself lacks quite a few of
the CUA keys (ask a Windows user how to move a window with the
keyboard, and s/he won't say "Alt-F7"), and some Windows applications
make this even worse (Adobe Reader egregiously so - you can't even use
Ctrl-Ins to copy to the clipboard, despite all the rest of Windows
supporting it).

But hey. MOST of the world uses the CUA keys. And yes, Emacs doesn't.
For better or for worse, you have to learn Emacs as its own thing.

ChrisA

Rustom Mody

unread,
Jul 25, 2016, 1:12:01 PM7/25/16
to
On Monday, July 25, 2016 at 10:32:45 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Jul 26, 2016 at 2:54 AM, Rustom Mody wrote:
> > The whole world uses cua keys:
> > https://en.wikipedia.org/wiki/IBM_Common_User_Access
> > [emacs] proudly sticks to what it was doing pre-cua
>
> Sadly, the "whole world" doesn't. Windows itself lacks quite a few of
> the CUA keys (ask a Windows user how to move a window with the
> keyboard, and s/he won't say "Alt-F7"), and some Windows applications
> make this even worse (Adobe Reader egregiously so - you can't even use
> Ctrl-Ins to copy to the clipboard, despite all the rest of Windows
> supporting it).

Ok I was speaking in-a-manner-of-speaking -- in two ways
All means most
Cua means the most common cua-keys — C-x C-c C-v
of which the first two specially are so deeply embedded into emacs as prefixes
for 100s of other functions that its hard to change without significant upheaval

>
> But hey. MOST of the world uses the CUA keys. And yes, Emacs doesn't.
> For better or for worse, you have to learn Emacs as its own thing.

Yeah…
Just playing around with magit
It the tool of choice in emacs world as a git client
And in all probability the best git client around

So yes emacs is unbeatable and emacs is obsolete
And that’s what makes it so annoying — impossible to find a replacement

Chris Angelico

unread,
Jul 25, 2016, 1:26:41 PM7/25/16
to
On Tue, Jul 26, 2016 at 3:11 AM, Rustom Mody <rusto...@gmail.com> wrote:
> On Monday, July 25, 2016 at 10:32:45 PM UTC+5:30, Chris Angelico wrote:
>> On Tue, Jul 26, 2016 at 2:54 AM, Rustom Mody wrote:
>> > The whole world uses cua keys:
>> > https://en.wikipedia.org/wiki/IBM_Common_User_Access
>> > [emacs] proudly sticks to what it was doing pre-cua
>>
>> Sadly, the "whole world" doesn't. Windows itself lacks quite a few of
>> the CUA keys (ask a Windows user how to move a window with the
>> keyboard, and s/he won't say "Alt-F7"), and some Windows applications
>> make this even worse (Adobe Reader egregiously so - you can't even use
>> Ctrl-Ins to copy to the clipboard, despite all the rest of Windows
>> supporting it).
>
> Ok I was speaking in-a-manner-of-speaking -- in two ways
> All means most
> Cua means the most common cua-keys — C-x C-c C-v
> of which the first two specially are so deeply embedded into emacs as prefixes
> for 100s of other functions that its hard to change without significant upheaval

Wrong - CUA's standard keys are Shift-Del, Ctrl-Ins, Shift-Ins for the
same operations. The alphabetics are not part of the CUA standard.
That said, though, most applications support both - primarily because
most GUI widgets are built to support both, and applications are
taught to respond to signals like 'paste'. This is one of those cases
where building your own is both way more work AND way less useful to
people; the same thing often happens when a program decides to be
"cute" with its UI and get rid of the title bar and regular frame,
painting its own window borders and stuff. It's a lot of work to make
that look decent, and then you end up with something that doesn't play
nicely with the rest of the system. You'd better have a really good
justification for that - and no, "it looks pretty" is NOT that
justification.

ChrisA

BartC

unread,
Jul 25, 2016, 1:34:11 PM7/25/16
to
On 25/07/2016 15:36, Random832 wrote:
> On Sun, Jul 24, 2016, at 18:13, BartC wrote:

[About C type specs]

I've replied briefly here as this is off-topic now:

http://pastebin.com/ZfcHqpXK

--
Bartc

Rustom Mody

unread,
Jul 25, 2016, 10:44:12 PM7/25/16
to
On Monday, July 25, 2016 at 10:56:41 PM UTC+5:30, Chris Angelico wrote:
> On Tue, Jul 26, 2016 at 3:11 AM, Rustom Mody wrote:
> > On Monday, July 25, 2016 at 10:32:45 PM UTC+5:30, Chris Angelico wrote:
> >> On Tue, Jul 26, 2016 at 2:54 AM, Rustom Mody wrote:
> >> > The whole world uses cua keys:
> >> > https://en.wikipedia.org/wiki/IBM_Common_User_Access
> >> > [emacs] proudly sticks to what it was doing pre-cua
> >>
> >> Sadly, the "whole world" doesn't. Windows itself lacks quite a few of
> >> the CUA keys (ask a Windows user how to move a window with the
> >> keyboard, and s/he won't say "Alt-F7"), and some Windows applications
> >> make this even worse (Adobe Reader egregiously so - you can't even use
> >> Ctrl-Ins to copy to the clipboard, despite all the rest of Windows
> >> supporting it).
> >
> > Ok I was speaking in-a-manner-of-speaking -- in two ways
> > All means most
> > Cua means the most common cua-keys — C-x C-c C-v
> > of which the first two specially are so deeply embedded into emacs as prefixes
> > for 100s of other functions that its hard to change without significant upheaval
>
> Wrong - CUA's standard keys are Shift-Del, Ctrl-Ins, Shift-Ins for the
> same operations. The alphabetics are not part of the CUA standard.
> That said, though, most applications support both - primarily because
> most GUI widgets are built to support both, and applications are
> taught to respond to signals like 'paste'.

You must be right
Ironically I learnt the word cua from emacs’ cua-mode which basically make
C-c C-x C-v (dont know which others) behave like the rest of the world expects.

Trouble is the first two are so deeply enmeshed into emacs that it does a bad job
of it. And conventional wisdom in emacs land is to avoid it and get used to the
(30+ year old!) emacs standard

Gregory Ewing

unread,
Jul 26, 2016, 3:21:26 AM7/26/16
to
BartC wrote:
> (Yes everyone uses T*a (pointer to T) instead of T(*a)[] (pointer to
> array of T), because, thanks to how C mixes up deferencing and indexing,
> the former can be accessed as a[i] instead of (*a)[i].
>
> But it's wrong, and leads to errors that the language can't detect. Such
> as when a points to a single element not a block:

This is an implementation issue, not a language issue.
A sufficiently pedantic implementation could and would
detect this kind of error at run time. Most implementations
of C are not that pedantic, but you can't blame the
language for that.

--
Greg

Gregory Ewing

unread,
Jul 26, 2016, 3:24:06 AM7/26/16
to
BartC wrote:
> But otherwise free-flowing English text is not a good comparison with a
> programming language syntax.

I think Python is more like poetry.

--
roses are red
violets are blue
is this the end
of the poem
no-one can tell
because there is no
end marker
thus spake the bdfl

Marko Rauhamaa

unread,
Jul 26, 2016, 3:56:28 AM7/26/16
to
Gregory Ewing <greg....@canterbury.ac.nz>:
Well, one of the novelties in C was the intentional blurring of the
lines between arrays and sequences of elements in memory. The
notation:

int a[3];

declares a as an array. However, the expression:

a

does not produce an array; instead, it produces a pointer to the first
element of the array. Even:

*&a

produces a pointer to the array's first element.


Marko

Gregory Ewing

unread,
Jul 26, 2016, 4:36:06 AM7/26/16
to
Marko Rauhamaa wrote:
> int a[3];
>
> a
>
> produces a pointer to the array's first element.

Yes, and that makes using true pointer-to-array types
in C really awkward. You're fighting against the way
the language was designed to be used.

If you use a language in an un-idiomatic way, you can't
really complain when you have difficulties as a result.

--
Greg

BartC

unread,
Jul 26, 2016, 6:11:32 AM7/26/16
to
(No, it's a language issue. Yes you might be able to have a sufficiently
complex (and slow) implementation that at best could detect errors at
runtime, but that's not much help.

It boils down to this: if you have a pointer type T*, does it point to a
standalone T object, or to an array or block of T objects?

The language allows a pointer P of type T* pointing to a single T object
to be accessed as P[i]. Apparently this is not seen as a problem...

(More observations about C here:

https://github.com/bartg/langs/blob/master/C%20Problems.md))

--
Bartc

Antoon Pardon

unread,
Jul 26, 2016, 10:33:35 AM7/26/16
to
Op 24-07-16 om 21:00 schreef Chris Angelico:
> A skilled craftsman in any field will choose to use quality tools.
> They save time, and time is money.[/quote]

Sure, but sometimes there is a flaw somewhere. A flaw whose
consequences can be reduced by using an extra tool. If that
is the case the real solution seems to get rid of the flaw
and not to use the tool.

So if someone argues there is a flaw somewhere, pointing to
tools doesn't contradict that.

--
Antoon.

Rob Gaddi

unread,
Jul 28, 2016, 4:01:31 PM7/28/16
to
Chris Angelico wrote:

> On Sat, Jul 23, 2016 at 9:13 PM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>>> One less thing to be programmed, one less thing for the user to
>>> remember. Just require pass any time you have an empty block, rather
>>> than try to remember where it is required and were it is optional.
>>
>> Actually, the requirement of a dummy statement is a slight annoyance for
>> the programmer. After deleting a statement, you must see if you have to
>> put in a pass statement. And after adding a statement, you may feel the
>> urge to remove the redundant pass statement.
>
> How often do you actually need empty statements, adding stuff,
> removing stuff, like that? Possibly there's a code smell here.
>
> ChrisA

Yeah, all the time.

try:
return self.cache[key]
except KeyError:
pass

lots... of... code...
self.cache[key] = newval
return newval

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com

Email address domain is currently out of order. See above to fix.

Chris Angelico

unread,
Jul 28, 2016, 4:12:08 PM7/28/16
to
On Fri, Jul 29, 2016 at 6:01 AM, Rob Gaddi
<rga...@highlandtechnology.invalid> wrote:
> Chris Angelico wrote:
>
>> On Sat, Jul 23, 2016 at 9:13 PM, Marko Rauhamaa <ma...@pacujo.net> wrote:
>>>> One less thing to be programmed, one less thing for the user to
>>>> remember. Just require pass any time you have an empty block, rather
>>>> than try to remember where it is required and were it is optional.
>>>
>>> Actually, the requirement of a dummy statement is a slight annoyance for
>>> the programmer. After deleting a statement, you must see if you have to
>>> put in a pass statement. And after adding a statement, you may feel the
>>> urge to remove the redundant pass statement.
>>
>> How often do you actually need empty statements, adding stuff,
>> removing stuff, like that? Possibly there's a code smell here.
>>
>> ChrisA
>
> Yeah, all the time.
>
> try:
> return self.cache[key]
> except KeyError:
> pass
>
> lots... of... code...
> self.cache[key] = newval
> return newval

It's common to *use* empty statements. What I'm saying is, do you
often have the situation Marko raises, where you need an empty
statement to which you add stuff and remove stuff, thus needing the
insertion/removal of 'pass'? Normally, you use 'pass' in a situation
where it's always going to remain an empty block.

ChrisA

Antoon Pardon

unread,
Jul 29, 2016, 4:59:29 AM7/29/16
to
Op 23-07-16 om 16:19 schreef Chris Angelico:
> On Sun, Jul 24, 2016 at 12:00 AM, BartC <b...@freeuk.com> wrote:
>> Or, for debugging or other reasons, when you need to comment out the
>> contents of a block. Then pass needs to be added.
> How often do you comment out an entire block and not its header? I
> don't remember the last time I did that. It's certainly not so common
> that adding 'pass' takes up a significant part of a debugging session.
>
> ChrisA

As BartC already mentions it happens fairly often during debugging.
Something like.

try:
Some code
except Some_Exception:
# Commented code for when I am debugging <Some code>
pass

D'Arcy J.M. Cain

unread,
Jul 29, 2016, 7:15:27 AM7/29/16
to
On Fri, 29 Jul 2016 10:58:35 +0200
Antoon Pardon <antoon...@rece.vub.ac.be> wrote:
> As BartC already mentions it happens fairly often during debugging.
> Something like.
>
> try:
> Some code
> except Some_Exception:
> # Commented code for when I am debugging <Some code>
> pass

I realize that that's a simplified example but really, isn't this just
as easy?

try:
Some code
# except Some_Exception:
# Commented code for when I am debugging <Some code>

If your code block really is one line is "pass #" really so much more
of a hardship than "#"? If it is a large block use "pass #@#" which is
easy to remove with a search and replace.

In any case, the rule about premature optimization for programs can
probably be applied to developers too. Is saving a "pass" once in a
while really where you need to focus your debugging efforts?

--
D'Arcy J.M. Cain
System Administrator, Vex.Net
http://www.Vex.Net/ IM:da...@Vex.Net
VoIP: sip:da...@Vex.Net

BartC

unread,
Jul 29, 2016, 9:15:23 AM7/29/16
to
On 29/07/2016 12:14, D'Arcy J.M. Cain wrote:
> On Fri, 29 Jul 2016 10:58:35 +0200
> Antoon Pardon <antoon...@rece.vub.ac.be> wrote:
>> As BartC already mentions it happens fairly often during debugging.
>> Something like.
>>
>> try:
>> Some code
>> except Some_Exception:
>> # Commented code for when I am debugging <Some code>
>> pass
>
> I realize that that's a simplified example but really, isn't this just
> as easy?
>
> try:
> Some code
> # except Some_Exception:
> # Commented code for when I am debugging <Some code>

Will it behave the same way when there is a Some_Exception exception?

--
Bartc

Ian Kelly

unread,
Jul 29, 2016, 9:42:06 AM7/29/16
to
Besides that, a try block on its own with no dependents blocks isn't even
legal syntax. You'd have to comment the try as well and replace it with "if
1" or similar.

Steven D'Aprano

unread,
Jul 29, 2016, 9:43:50 AM7/29/16
to
Of course it won't, which is why I don't believe all these folks who claim
that they regularly ("all the time", "fairly often") replace except blocks
with `pass`. I call shenanigans -- perhaps you do it *occasionally*, but as
a general rule, you can rarely replace the exception handler with a
do-nothing clause and expect your code to work:

try:
block
except SomeException:
handle error
process

If you remove the error handling block, replacing it with `pass`, in general
your code will just break again as soon as it continues processing.

Antoon Pardon

unread,
Jul 29, 2016, 9:47:33 AM7/29/16
to
Op 29-07-16 om 13:14 schreef D'Arcy J.M. Cain:
> On Fri, 29 Jul 2016 10:58:35 +0200
> Antoon Pardon <antoon...@rece.vub.ac.be> wrote:
>> As BartC already mentions it happens fairly often during debugging.
>> Something like.
>>
>> try:
>> Some code
>> except Some_Exception:
>> # Commented code for when I am debugging <Some code>
>> pass
> I realize that that's a simplified example but really, isn't this just
> as easy?
>
> try:
> Some code
> # except Some_Exception:
> # Commented code for when I am debugging <Some code>

That code doesn't behave the same.

> If your code block really is one line is "pass #" really so much more
> of a hardship than "#"? If it is a large block use "pass #@#" which is
> easy to remove with a search and replace.

Whose talking about hardschip? I don't trouble my self with removing
the pass statement when the debugging code is active. But Chris seemed
to suggest a situation like above was really rare, so I answered his
question.

--
Antoon.

Antoon Pardon

unread,
Jul 29, 2016, 9:56:04 AM7/29/16
to
Op 29-07-16 om 15:43 schreef Steven D'Aprano:
> Of course it won't, which is why I don't believe all these folks who claim
> that they regularly ("all the time", "fairly often") replace except blocks
> with `pass`. I call shenanigans -- perhaps you do it *occasionally*, but as
> a general rule, you can rarely replace the exception handler with a
> do-nothing clause and expect your code to work:
>
> try:
> block
> except SomeException:
> handle error
> process
>
> If you remove the error handling block, replacing it with `pass`, in general
> your code will just break again as soon as it continues processing.

I think the case where you just want to ignore the exception, but it can
at times be useful to get some extra logging information for debuging
purposes, is not that rare as you seem to suggest.

--
Antoon Pardon

Steven D'Aprano

unread,
Jul 29, 2016, 10:38:43 AM7/29/16
to
I think I can count the number of times I've wanted to ignore an exception
on the fingers of one hand. And when I did, there was no need to debug it,
because I only ignore expected failures. There's nothing to debug.

But even if you do it all the time, how do you "get some extra logging
information" by replacing the "except" block with `pass`? If you replaced
the "except" block with a call to the logger, that would be one thing.
But "pass", that won't do the job.

D'Arcy J.M. Cain

unread,
Jul 29, 2016, 12:20:41 PM7/29/16
to
On Fri, 29 Jul 2016 14:15:01 +0100
BartC <b...@freeuk.com> wrote:
> > try:
> > Some code
> > # except Some_Exception:
> > # Commented code for when I am debugging <Some code>
>
> Will it behave the same way when there is a Some_Exception exception?

Of course not. The person writing that was an idiot.

Oh wait - I wrote that. Damn! There must have been a reasonable
excuse then.

Naturally that part of my message was the only thing commented on. I
suppose people stopped reading after that flub and missed my insightful
comment on premature developer optimization.

Getting more coffee now.

D'Arcy J.M. Cain

unread,
Jul 29, 2016, 12:29:11 PM7/29/16
to
On Fri, 29 Jul 2016 15:55:07 +0200
Antoon Pardon <antoon...@rece.vub.ac.be> wrote:
> I think the case where you just want to ignore the exception, but it
> can at times be useful to get some extra logging information for
> debuging purposes, is not that rare as you seem to suggest.

The way I handle that is:

DEBUG = False # near top of file
...
try:
block
except SomeException:
if DEBUG: log("Blah blah blah")

Usually it's in a class so it would be "self.DEBUG". You can also get
fancy with debug levels instead of True and False.

My theory is that if I need to log it today there's a more than zero
chance I might need to log it again one day.

Antoon Pardon

unread,
Jul 29, 2016, 2:34:37 PM7/29/16
to
Op 29-07-16 om 16:38 schreef Steven D'Aprano:
> On Fri, 29 Jul 2016 11:55 pm, Antoon Pardon wrote:
>
>> Op 29-07-16 om 15:43 schreef Steven D'Aprano:
>>> Of course it won't, which is why I don't believe all these folks who
>>> claim that they regularly ("all the time", "fairly often") replace except
>>> blocks with `pass`. I call shenanigans -- perhaps you do it
>>> *occasionally*, but as a general rule, you can rarely replace the
>>> exception handler with a do-nothing clause and expect your code to work:
>>>
>>> try:
>>> block
>>> except SomeException:
>>> handle error
>>> process
>>>
>>> If you remove the error handling block, replacing it with `pass`, in
>>> general your code will just break again as soon as it continues
>>> processing.
>>
>> I think the case where you just want to ignore the exception, but it can
>> at times be useful to get some extra logging information for debuging
>> purposes, is not that rare as you seem to suggest.
>
> I think I can count the number of times I've wanted to ignore an exception
> on the fingers of one hand. And when I did, there was no need to debug it,
> because I only ignore expected failures. There's nothing to debug.

You really should stop, generalising your own situation.

> But even if you do it all the time, how do you "get some extra logging
> information" by replacing the "except" block with `pass`? If you replaced
> the "except" block with a call to the logger, that would be one thing.
> But "pass", that won't do the job.

You don't seem to understand. There is no real except block to be replaced
by pass. There is sometime an except block added (or uncommented) to get
logging information.

--
Antoon Pardon.

Terry Reedy

unread,
Jul 29, 2016, 3:43:29 PM7/29/16
to
On 7/29/2016 4:58 AM, Antoon Pardon wrote:
> Op 23-07-16 om 16:19 schreef Chris Angelico:
>> On Sun, Jul 24, 2016 at 12:00 AM, BartC <b...@freeuk.com> wrote:
>>> Or, for debugging or other reasons, when you need to comment out the
>>> contents of a block. Then pass needs to be added.
>> How often do you comment out an entire block and not its header? I
>> don't remember the last time I did that. It's certainly not so common
>> that adding 'pass' takes up a significant part of a debugging session.
>>
>> ChrisA
>
> As BartC already mentions it happens fairly often during debugging.
> Something like.
>
> try:
> Some code
> except Some_Exception:
> # Commented code for when I am debugging <Some code>
> pass

So put in 'pass' whether or not there is no debugging code,
commented-out debugging code, or debugging code that runs, or whatever.

--
Terry Jan Reedy

BartC

unread,
Jul 29, 2016, 4:19:19 PM7/29/16
to
But that's inelegant.

The language requires that blocks always contains 1 or more statements.
Fair enough, except that 0 statements are often needed so that a dummy
statement - 'pass' - is required just to keep the code legal.

That's untidy, as is your suggestion to keep the dummy statement lying
around anyway so that the number of statements will always be N+1 and
can never reach 0 as N changes.


--
Bartc

Marko Rauhamaa

unread,
Jul 29, 2016, 6:01:42 PM7/29/16
to
BartC <b...@freeuk.com>:
Yes, untidy, albeit only slightly. What you gain is visible blocks.

The gods have spoken and have decided for visibility over philosophical
elegance.

I *have* been hit with analogous untidiness in classic C, which didn't
accept empty structs or empty arrays. I was generating C arrays from a
compiler and--annoyingly--had to place special checks in the compiler to
place a dummy element in an array where none would be generated
naturally.

I have also had to spend some time debugging some segmentation faults
caused by #ifdef's and surprising sizeof calculations in (classic) C and
(modern) C++. Look at this structure:

struct S {
int x[0];
};

Gcc claims sizeof(struct S) == 0 in C and C++.

Well, that's natural, right?

How about:

struct S {
};

Now gcc claims sizeof(struct S) == 0 if the language is C but
sizeof(struct S) == 1 if the language is C++.

That's because Stroustrup is allergic to 0-size data structures the way
GvR is allergic to 0-size blocks.


Marko

Steven D'Aprano

unread,
Jul 29, 2016, 11:36:06 PM7/29/16
to
On Sat, 30 Jul 2016 06:19 am, BartC wrote:

> The language requires that blocks always contains 1 or more statements.
> Fair enough, except that 0 statements are often needed

They really aren't.

The standard library uses more "pass" statements than most code I've seen,
because of the large number of abstract methods and tests that use dummy
classes or methods. If you are writing library code, or a framework, with
lots of "do nothing" blocks that the caller is supposed to override, you
may find yourself doing the same. Even so, the number of "pass" statements
is a tiny proportion of code, less than one percent for Python 3.6:

[steve@ando Lib]$ wc -l *.py */*.py | tail -n 1
541022 total
[steve@ando Lib]$ grep "pass$" *.py */*.py | wc -l
3286


Over two thirds of them are from the test suite:

[steve@ando Lib]$ grep "pass$" test/*.py | wc -l
2270

I feel confident in saying that if you find yourself writing "pass" in
application code (as opposed to writing a framework or unit tests for a
library) more than one time in a 500 lines of code, you're doing something
wrong. But even if it were as high as one time in 100 lines, it is still
not an onerous requirement.

You should see how many times Ruby programmers have to write "end", 99.9% of
which are unneeded but forced on them by the language.

Steven D'Aprano

unread,
Jul 29, 2016, 11:50:01 PM7/29/16
to
I'm not just generalising from code I've written. I'm generalising from code
I've reviewed, code I've read, code I've seen others admire, code I've seen
others mock and laugh at, and best practices I've read about. That's
called "learning to be a better programmer".


>> But even if you do it all the time, how do you "get some extra logging
>> information" by replacing the "except" block with `pass`? If you replaced
>> the "except" block with a call to the logger, that would be one thing.
>> But "pass", that won't do the job.
>
> You don't seem to understand. There is no real except block to be replaced
> by pass. There is sometime an except block added (or uncommented) to get
> logging information.

Perhaps its *you* who doesn't understand. The subject line talks
about "empty code blocks", and Bart has suggested that instead of having to
write


try:
something
except SomeException:
pass
process


(which he considers far too difficult) we should allow empty code blocks:


try:
something
except SomeException:
process


because apparently saving that one indented line with "pass" makes all the
difference in language usability. That lead to Chris asking how common it
was to do this. That's when Bart said that he frequently *replaced* an
existing except block with "pass":


# before
try:
something
except SomeException:
handle error
handle it some more
process

# after
try:
something
except SomeException:
pass
process


At which point *you agreed with him*:

[quote]
As BartC already mentions it happens fairly often during debugging.
Something like.

try:
Some code
except Some_Exception:
# Commented code for when I am debugging <Some code>
pass
[end quote]



So now you're changing your story, and claiming that you're not actually
replacing an existing except block with pass (because I think any
experienced Python developer, which Bart is not, realises that's not likely
to work). Now you've got a use-case where we start with:

# before
some code
more processing

and add an entire try...except around it:

# step 1
try:
some code
except SomeException:
debugging code
more processing

*and then* comment out the debugging code and replace it with pass:

# after, as stated by you
try:
some code
except SomeException:
# debugging code
pass
more processing


Of course it's legitimate to wrap some failing code in a temporary
try...except block for debugging purposes. But that's not an empty code
block, and its not "pass", and it's not relevant to Chris' question.

And what happens once you have finished debugging the code? According to
your post, you comment out the debugging code, replacing it by "pass". And
you do this *frequently*.

Okay, if you say you do that, I have to believe you. If we take you at your
word, then we can only conclude that your code is littered with the
detritus of old debugging code and unnecessary try...except blocks which do
nothing. That's practically the definition of *poor programming*, leaving
old code commented out to rot, but if you say that's what you do, who am I
to argue that you don't?

Since I don't actually believe you are that poor a programmer, I suspect
that what you actually do is not replace the debugging code with "pass",
like you claim, but that once you have finished debugging that section of
the code you remove the unneeded try...except block and dead, unused
debugging code, returning it to the "before" state.

D'Arcy's suggestion of leaving the debugging code in with a runtime switch
to turn it on and off also makes sense. I'm partial to switching on the
special __debug__ global. But we're getting further and further away from
Bart's scenario, of a bare "pass". *That's* what I don't believe in: this
supposed scenario where people have existing code blocks that they have to
replace with "pass", and that happens *frequently enough to matter*.

And of course as D'Arcy has pointed out, these two are not the same:

# before
some code

# after
try:
some code
except SomeException:
pass

To make the second one equivalent to the first, one should use *raise*, not
pass. In which case you could even leave your debugging code in there,
uncommented out:

try:
some code
except SomeException:
raise
debugging code


all the better to confuse those who have to maintain the program in your
absence.

BartC

unread,
Jul 30, 2016, 6:15:24 AM7/30/16
to
On 30/07/2016 04:35, Steven D'Aprano wrote:
> On Sat, 30 Jul 2016 06:19 am, BartC wrote:
>
>> The language requires that blocks always contains 1 or more statements.
>> Fair enough, except that 0 statements are often needed
>
> They really aren't.
>
> The standard library uses more "pass" statements than most code I've seen,
> because of the large number of abstract methods and tests that use dummy
> classes or methods. If you are writing library code, or a framework, with
> lots of "do nothing" blocks that the caller is supposed to override, you
> may find yourself doing the same. Even so, the number of "pass" statements
> is a tiny proportion of code, less than one percent for Python 3.6:
>
> [steve@ando Lib]$ wc -l *.py */*.py | tail -n 1
> 541022 total
> [steve@ando Lib]$ grep "pass$" *.py */*.py | wc -l
> 3286
>
>
> Over two thirds of them are from the test suite:
>
> [steve@ando Lib]$ grep "pass$" test/*.py | wc -l
> 2270

Interesting use of 'pass' in this example:

http://pastebin.com/aYJdgEL4

(I do believe he's using 'pass' as 'end'! Although he misses some out in
that case.)


>
> I feel confident in saying that if you find yourself writing "pass" in
> application code (as opposed to writing a framework or unit tests for a
> library) more than one time in a 500 lines of code, you're doing something
> wrong. But even if it were as high as one time in 100 lines, it is still
> not an onerous requirement.
>
> You should see how many times Ruby programmers have to write "end", 99.9% of
> which are unneeded but forced on them by the language.

Think of it as a pattern. In one language, I used (Algol68-style), a
simple if was:

if a then b else c fi

which could also be written more compactly, as suits an expression:

( a | b | c )

Then the 'fi' (that is, 'end' or 'end if') is just closing the construct
started with 'fi', in the same way that ')' closes the opening '('.

As I've mentioned, Python also uses explicit block delimiters in the
form of else, elif, except, finally (and whichever ones I've misssed):

if x: a; b elif y: c; d elif z: e; f else: g

In the above syntax, it would be:

if x then a; b elsif y then c; d elsif z then e; f else g fi

Doesn't it look like there's something missing in the Python? Both the
'fi' or 'end', and the possibility of an 'h' statement.

Note the Algol68-style style is more free-format where indents are not
significant.

Anyway, if you're going to talk about annoying things forced upon you by
the language, what about:

":" after "else"

"()" in "def fn():"

"()" in "print (x)" for Python 3

"for i in range(N):" just to repeat a block N times...

That's apart from the obligatory indents which, with an 'end'-delimited
scheme, are not always necessary.

--
Bartc

Chris Angelico

unread,
Jul 30, 2016, 7:26:01 AM7/30/16
to
On Sat, Jul 30, 2016 at 8:15 PM, BartC <b...@freeuk.com> wrote:
> Anyway, if you're going to talk about annoying things forced upon you by the
> language, what about:
>
> "()" in "print (x)" for Python 3

Why are you singling out print? It's just a function like any other.
Are you complaining about the way function calls need parentheses?

ChrisA

Rustom Mody

unread,
Jul 30, 2016, 7:39:59 AM7/30/16
to
On Saturday, July 30, 2016 at 4:56:01 PM UTC+5:30, Chris Angelico wrote:
> On Sat, Jul 30, 2016 at 8:15 PM, BartC wrote:
> > Anyway, if you're going to talk about annoying things forced upon you by the
> > language, what about:
> >
> > "()" in "print (x)" for Python 3
>
> Why are you singling out print? It's just a function like any other.
> Are you complaining about the way function calls need parentheses?

Its a function… ok.
Its ‘just’ a function… Arguable

For example:

- Prior Art: Its builtin and special in Fortran, Pascal, Basic
- More immediate : It was a special in python2
- Poorer error catching: What was a straight syntax error is now a lint-catch (at best)
[print (x) for x in range(20)]

Chris Angelico

unread,
Jul 30, 2016, 7:49:25 AM7/30/16
to
On Sat, Jul 30, 2016 at 9:39 PM, Rustom Mody <rusto...@gmail.com> wrote:
> On Saturday, July 30, 2016 at 4:56:01 PM UTC+5:30, Chris Angelico wrote:
>> On Sat, Jul 30, 2016 at 8:15 PM, BartC wrote:
>> > Anyway, if you're going to talk about annoying things forced upon you by the
>> > language, what about:
>> >
>> > "()" in "print (x)" for Python 3the modulo operator
>>
>> Why are you singling out print? It's just a function like any other.
>> Are you complaining about the way function calls need parentheses?
>
> Its a function… ok.
> Its ‘just’ a function… Arguable
>
> For example:
>
> - Prior Art: Its builtin and special in Fortran, Pascal, Basic

And it's not built-in or special in C, or a bunch of other languages.

> - More immediate : It was a special in python2

Which resulted in unmitigatable problems, such as that you can't mock
it for testing or redirection purposes, and it demands syntactic magic
to do its work - for instance, the only option is a "soft space" in
place of a newline, where the print function allows full customization
of both end= and sep=. The print function is DEFINITELY an
improvement. I would also posit that an sprintf() built-in function
instead of str.__mod__ would have meant there was less kickback
against printf-style formatting, because it wouldn't have had the
strange behaviour around single-argument use. (It's pretty simple to
write, of course, but built-ins are extremely significant to
perception. def sprintf(fmt, *args): return fmt % args) Syntax is NOT
always an improvement.

> - Poorer error catching: What was a straight syntax error is now a lint-catch (at best)
> [print (x) for x in range(20)]

Huh? Aside from the fact that you're constructing a useless list of
Nones, what's the error?

Also: Why is print special here? Maybe you accidentally called
frobnicate on those x's and you shouldn't have. How is Python supposed
to know that that's an error?

ChrisA

Rustom Mody

unread,
Jul 30, 2016, 8:11:20 AM7/30/16
to
On Saturday, July 30, 2016 at 5:19:25 PM UTC+5:30, Chris Angelico wrote:
Huh²

Are you seriously suggesting that python-3’s behavior below is better IN
THIS INSTANCE than python-2’s?

[That there may be other reasons that outweigh this one for print-as-function
is not something I am disputing. I was solely disputing your ‘just’]

Python 2.7.12 (default, Jul 1 2016, 15:12:24)
>>> [print(x) for x in range(10)]
File "<stdin>", line 1
[print(x) for x in range(10)]
^
SyntaxError: invalid syntax
>>>

Python 3.5.2 (default, Jul 5 2016, 12:43:10)

>>> [print(x) for x in range(10)]
0
1
2
3
4
5
6
7
8
9
[None, None, None, None, None, None, None, None, None, None]
>>>

Chris Angelico

unread,
Jul 30, 2016, 8:23:12 AM7/30/16
to
I still don't understand your complaint. How is this "better/worse
error checking"? All you're showing me is the same line of code you
showed above, plus what it does in Py2 and Py3, which I know already.
You haven't explained why this is such a great feature in Py2 that got
lost in Py3.

And hey. If you want to print out the numbers 0 through 9, Py3 offers
a pretty concise way to spell that:

>>> print(*range(10), sep='\n')
0
1
2
3
4
5
6
7
8
9
>>>

Beat that, print statement.

ChrisA

BartC

unread,
Jul 30, 2016, 8:27:27 AM7/30/16
to
On 30/07/2016 12:49, Chris Angelico wrote:
> On Sat, Jul 30, 2016 at 9:39 PM, Rustom Mody <rusto...@gmail.com> wrote:

>> Its a function… ok.
>> Its ‘just’ a function… Arguable
>>
>> For example:
>>
>> - Prior Art: Its builtin and special in Fortran, Pascal, Basic
>
> And it's not built-in or special in C, or a bunch of other languages.

The parentheses are a nuisance in C too, as are obligatory format codes.
And C created a lot of bad precedences (literally in the case of binary
operators!)

For an informal, rapid development language, the less formality about
these things the better.

>> - More immediate : It was a special in python2
>
> Which resulted in unmitigatable problems, such as that you can't mock
> it for testing or redirection purposes,

The language finds other solutions so that programs using "print A"
don't need changing. Perhaps 'print <list>' is syntactic sugar for
'_print (<list>' or something.

and it demands syntactic magic
> to do its work - for instance, the only option is a "soft space" in
> place of a newline, where the print function allows full customization
> of both end= and sep=.

This is one thing I can never get right in Python: controlling when a
newline is or isn't generated and what happens with separators.

(In fact when I used Python as a target language, I had to generate
calls to sys.stdout.write instead as it had more predictable behaviour.)

So if it's the advantage of using () then it's one I never benefit from!

Newline control should be one of the simplest things in the language,
part of the very first programs you write.

(Some languages use 'write' or 'writeln', or 'print' or 'println'; what
could be simpler? Or you just explicitly output a "\n" string.)

--
Bartc


Rustom Mody

unread,
Jul 30, 2016, 8:31:45 AM7/30/16
to
On Saturday, July 30, 2016 at 5:53:12 PM UTC+5:30, Chris Angelico wrote:
Heh Cute! Thanks!!

> 0
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
> >>>
>
> Beat that, print statement.

What makes you think I wanted to print those numbers??
Maybe I wanted a list of 10 None-s??

Point being that when one mixes up 2 things like that its anybody’s guess
which is the primary (central) effect and which the ‘side’ effect

Chris Angelico

unread,
Jul 30, 2016, 8:34:39 AM7/30/16
to
On Sat, Jul 30, 2016 at 10:27 PM, BartC <b...@freeuk.com> wrote:
>> where the print function allows full customization
>> of both end= and sep=.
>
>
> This is one thing I can never get right in Python: controlling when a
> newline is or isn't generated and what happens with separators.
>
> (In fact when I used Python as a target language, I had to generate calls to
> sys.stdout.write instead as it had more predictable behaviour.)
>
> So if it's the advantage of using () then it's one I never benefit from!
>
> Newline control should be one of the simplest things in the language, part
> of the very first programs you write.
>
> (Some languages use 'write' or 'writeln', or 'print' or 'println'; what
> could be simpler? Or you just explicitly output a "\n" string.)

Here, look:

print(obj) # with newline
print(obj, end="") # without newline

Easy, isn't it?

Start playing to the language's strengths instead of fighting against
them. Keyword arguments are a Python feature that I frequently yearn
for in other languages. Use them!

ChrisA

BartC

unread,
Jul 30, 2016, 8:40:08 AM7/30/16
to
On 30/07/2016 13:22, Chris Angelico wrote:

>>>> print(*range(10), sep='\n')
> 0
> 1
> 2
> 3
> 4
> 5
> 6
> 7
> 8
> 9
>>>>
>
> Beat that, print statement.

for i in range(10): print i

Same number of characters, but a lot less punctuation!

--
Bartc

Chris Angelico

unread,
Jul 30, 2016, 8:45:19 AM7/30/16
to
On Sat, Jul 30, 2016 at 10:31 PM, Rustom Mody <rusto...@gmail.com> wrote:
> What makes you think I wanted to print those numbers??
> Maybe I wanted a list of 10 None-s??

Because you NEVER SAID what you wanted! How can you talk about error
detection if you won't say what the programmer's intention was? You're
forcing us to guess, and then complaining that I guessed wrongly.

> Point being that when one mixes up 2 things like that its anybody’s guess
> which is the primary (central) effect and which the ‘side’ effect

Okay, so my revised guess is: Console output is a primary effect and
should not have a secondary effect of returning None. Great. Now
please go and build yourself a language in which list.append is a
statement (because it shouldn't return None either), etc, etc, just in
case someone uses them wrongly. I'll keep using Python, where it's
normal for a side-effect-y function to return None - it's much
simpler. And even in Pike, where void functions are a real thing, it's
possible to recast the function so you can call it in an expression
context - and the same thing happens. Truly void functions are nothing
but parser convenience.

ChrisA

Chris Angelico

unread,
Jul 30, 2016, 8:47:33 AM7/30/16
to
So, no improvement - exactly equal. And no longer a single expression,
ergo no longer valid in as many contexts. (Also, it requires the use
and damage of some iterator variable, which may be significant in some
contexts.)

ChrisA

Chris Angelico

unread,
Jul 30, 2016, 8:48:02 AM7/30/16
to
On Sat, Jul 30, 2016 at 10:47 PM, Chris Angelico <ros...@gmail.com> wrote:
> So, no improvement - exactly equal. And no longer a single expression,
> ergo no longer valid in as many contexts. (Also, it requires the use
> and damage of some iterator variable, which may be significant in some
> contexts.)

In case it's not clear: </tongue_in_cheek>

ChrisA

Steven D'Aprano

unread,
Jul 30, 2016, 9:06:24 AM7/30/16
to
On Sat, 30 Jul 2016 08:15 pm, BartC wrote:

> Interesting use of 'pass' in this example:
>
> http://pastebin.com/aYJdgEL4
>
> (I do believe he's using 'pass' as 'end'! Although he misses some out in
> that case.)

I wouldn't call it so much "interesting" as "a good example of how not to
program".

All languages -- human and programming -- involve certain quirks, or
features which are matters of taste. If it a sign of a poor programmer that
ignores the common idioms of a language and writes in another
language's "grammar".

"If so smart Yoda is, how come English speak he cannot?"

People are more forgiving off grammatical errors and weird idioms than
computer programs, but still, there are conventions to follow. In English,
we can talk about having a quick meal of fast food, but not a fast meal of
quick food. Our computers are powerful, never mighty, and if we ever invent
a time machine, we'll travel into the past, not onto the past.

You can get away with breaking a language's idioms for humour:

https://www.youtube.com/watch?v=MNyG-xu-7SQ

or, if you're *really* talented, as art. See, for example, James Joyce's
Finnegan's Wake, which is as unidiomatic as it is possible to be while
still being (just barely) English, but deliberately so.

(As opposed to "ee cummings", who was and is lauded far beyond his actual
talent.)

Th same principles apply to programming languages. But outside of highly
optimized code, which is often ugly, or examples of code as art (like code
golf, Obfuscated C and Underhanded C competitions, multi-language hybrid
code, esoteric languages etc.), the aim of programming should be to
maximize *human* communication. And that usually means writing in the
idiomatic style of the natives. There are no awards for trying to hammer
the round pegs of Algol grammar into the square holes of the Python
interpreter.

(1) Using "pass" as a form of "end" is simply bizarre.

(2) Python allows the semi-colon for the convenience of command-line users,
where it is sometimes difficult to write multiple lines of code. Using it
inside a .py file is a sign of somebody who is not a native speaker.

(3) Separating statements by variable numbers of spaces, between 1 and 13 by
my count, is just weird.

Given the lack of Python fluency, the lack of documentation and meaningful
comments, the unusual (for Python) idioms that hurt readability, and some
very odd names (there is one constant called "ONE" with the value
1073741824), the overall impression I get is that the author of that file
simply isn't a good programmer.


[...]
> As I've mentioned, Python also uses explicit block delimiters in the
> form of else, elif, except, finally (and whichever ones I've misssed):


You are wrong. They are not delimiters. They *begin* a new block, they don't
end the previous one except as a side effect of beginning a new block.

if condition:
block
new block

It is the dedent (outdent) that ends the if block. "new block" is permitted
to be an elif or else statement, of course, but you cannot write:


if condition:
block
else: statement

because "else" is not an "end of if" statement. It *begins* a new statement.


> if x: a; b elif y: c; d elif z: e; f else: g

That's not legal Python syntax.


> In the above syntax, it would be:
>
> if x then a; b elsif y then c; d elsif z then e; f else g fi
>
> Doesn't it look like there's something missing in the Python?

No it does not.



> Both the
> 'fi' or 'end', and the possibility of an 'h' statement.
>
> Note the Algol68-style style is more free-format where indents are not
> significant.

Good for Algol. To my eyes, that makes it harder to read: too many
unneeded "ends", to great a risk that the visual structure of the code
doesn't match the logical structure of the code.


> Anyway, if you're going to talk about annoying things forced upon you by
> the language, what about:
>
> ":" after "else"

What about it? When you write a list of items in English, it is more
idiomatic and natural to end the clause with a semi-colon:

- item one
- item two
- item three


than without it.

I've read Cobra code which is very like Python except (among other changes)
they've dropped the semi-colons It simply looks wrong Like sentences
without punctuation Or perhaps like an painting on a wall just every so
slightly on an angle


> "()" in "def fn():"

I could go either way with that.


> "()" in "print (x)" for Python 3

Why? Do you object to other functions using parentheses?


> "for i in range(N):" just to repeat a block N times...

Why should there be special syntax just for repeating a block N times?
There's a general purpose for-loop which performs iteration. Why do you
need special syntax to do what it already does?

We have a general "if" clause for doing conditional branching. Would you
insist on a special purpose if syntax for testing if a number is 2?

if number == 1: # general case
if number == 7921 # general case
iftwo number: # special syntax


> That's apart from the obligatory indents which, with an 'end'-delimited
> scheme, are not always necessary.

Of course they're necessary. The participants of the old "indent style wars"
of the 80s and 90s didn't agree on much, but they did agree on one thing:

- if you write code without indentation that matches the logical structure
of the code, you're a bad programmer.

End of story. As far as I am concerned, the 97% of languages which allow the
visual structure of the code to differ from their logical structure are BAD
LANGUAGES.

Chris Angelico

unread,
Jul 30, 2016, 9:37:00 AM7/30/16
to
On Sat, Jul 30, 2016 at 11:06 PM, Steven D'Aprano <st...@pearwood.info> wrote:
>> "for i in range(N):" just to repeat a block N times...
>
> Why should there be special syntax just for repeating a block N times?
> There's a general purpose for-loop which performs iteration. Why do you
> need special syntax to do what it already does?

Python could have chosen to make integers iterable, such that you say:

for i in 10:

but I don't think it really improves readability. It wouldn't
materially damage the language, though - the 'for' loop still does
exactly what it does, the rules are still just as simple. The only
question would be: why can't floats be iterable too? I mean, "for i in
3.5" should start half way down the loop body, complete that loop, and
then do three complete loops.

ChrisA
It is loading more messages.
0 new messages