Using the Python Interpreter as a Reference

S

Steven D'Aprano

I'm inclined toward an alternative: explicit recursion. Either a
different syntax, or a special-case on the use of the function's own
name, but whichever syntax you use, it compiles in a "recurse" opcode.
That way, if name bindings change, it's still going to recurse -
something few languages guarantee, and therefore few languages can
optimize.

As I recall, Forth uses (or used) a special RECURSE word which turned on
the recursion bit while compiling, so that the compiled word could see
itself.

By memory, the (incomplete) definition:

: fact dup 1- fact * ;

would fail, unless you happened to already have another word called fact
existing at compilation time. To make it recurse correctly, the compiler
needs to make sure that the namespace fact sees includes itself:

RECURSE : fact dup 1- fact * ;

which should work, apart from the embarrassing fact that I don't recall
the syntax for conditional jumps and so the recursion never terminates.

:)
 
D

Dave Angel

As I recall, Forth uses (or used) a special RECURSE word which turned on
the recursion bit while compiling, so that the compiled word could see
itself.

By memory, the (incomplete) definition:

: fact dup 1- fact * ;

would fail, unless you happened to already have another word called fact
existing at compilation time. To make it recurse correctly, the compiler
needs to make sure that the namespace fact sees includes itself:

RECURSE : fact dup 1- fact * ;

which should work, apart from the embarrassing fact that I don't recall
the syntax for conditional jumps and so the recursion never terminates.

:)
The way I remember it, the current definition was "smudged" which made
it invisible (it basically changed the name to something unlikely)
during the compilation. After all, if you actually ran it at compile
time (which was frequently done), you could fall right into
uninitialized space. Anyway, some implementations had an immediate
SMUDGE word, which toggled the smudge bit and made it visible again.

Other implementations had an immediate word RECURSE, which compiled in
whatever word was being currently defined.
I'm pretty sure neither FIG nor Forth79 had either of these. But I
don't recall the ANSI standard (X3J14 ?), even though I was officially
an observer. I can't even remember what happened to my printed copy of
the standard.

The easiest word for conditional is IF/ELSE/THEN. IF will skip to the
ELSE or THEN if the condition is false. So something resembling:

: fact dup 1- dup 0<> if recurse * then ;

might do it. That's very rough, however. It's been a long time.
 
D

DevPlayer

Why should we enforce how many spaces a tab is set to? That is literally
only visible to the editor, not the compiler. (Unless the parser is
particularly stupid and merely substitutes X spaces for a tab every time
it sees one.)

Mixed spaces and tabs in an indent are ambiguous, and so raises
SyntaxError (or at least it *should* raise SyntaxError). But separate
code blocks can use different absolute indent levels without ambiguity,
so long as the relative indentation is consistent:

def ham(): # tab stops at 4 and 8
    do(a)
    do(b)
    if c:
        do(c)
    else:
        do(d)

def spam(): # tab stops at 8 and 12
        do(a)
        do(b)
        if c:
            do(c)
        else:
            do(d)

There is no meaningful difference in indentation between ham and spam
above. In either case, I could replace spaces with tabs to get the same
relative indents regardless of the absolute indentation.

I can appreciate the aesthetic argument that *within a single file*,
indentation should be consistent. But it's not logically necessary for
the parser: it need only be consistent within a single code unit
(function or class usually). In other words: syntax should only care
about relative indentation, absolute indentation belongs as a coding
standard.

Great point. Your point is why I started writting my own little Python
parser/scanner (as an pet project/lesson project) and is in part, why
I wrote my little reindent() in the first place. I am/was trying to
figure out the algorithim for how Python's indent/dedents made logical
"code blocks" or "closures" or whatever they are called. That and see
if there was a way to interpret docstrings in various formats.

I often get indentation syntax errors when I cut and paste
stackflow.com, devprogrammer.com, daniweb.com, etc. code snippets into
my various IDEs/ editors and I wanted to make a little tabnanny of my
own. Some of the IDEs and editors (Editra) allow plugins. So I wanted
to get a baseline for the various plugins.

So I call the reindent() after I call the blocker(), which determines
a block by -releative- indent/dedent as +1 or, 0 or -1 whether that be
+4 spaces, +2 spaces, +1 tab or -3 spaces, whatever...; as you, Steve,
mentioned indent is not fixed but relative.

(btw I'v posted this in this topic because I thought it could
contribute to how Unit's choice of how indents are handled my benefit
from this discussion).

My thoughts on tab verse space chars;, for most old and even current
commandline interfaces, text editors, and historically line printers,
tabs simply acted like a macro to move x number of fixed spaces. It
wasn't until varible width fonts, kerning, and other advanced printing
techniques became mainstream<- did space chars differ in meaning from
tab chars, exception perhaps being file storage space (way back in the
day). I only say this because I can't stand hitting the right and left
arrow keys or using multiple fingers to move left and right 3 more
times then I have to while editing my text. I -feel- I move faster
around my text files with tabs then I do with 4 spaces.

They only annoyance I've had with Python's flexiblity with indent
using tab and or spaces is the docstrings.
\t = tab
def myfunc():
\t"""here is my docstring that bla bla bla's
\t\tand indented do da days...
\t"""

verse (s = space)
def myfunc():
ssss"""here is my docstring that bla bla bla's
ssssssssand indented do da days...
ssss"""

verse space = tab or space
def myfunc():
"here is my docstring that bla bla bla's"\
" and indented do da days..."\
"\n"

verse the legal and sometimes seen form:
def myfunc():
\tmyval = somefunc( arg0, arg1, arg2, lotsofargs,
\t\tsssspaces_to_align_arg_to_arg0)

If you strip the text and display it using basic reformatting in fixed
font, like in the python interpreter, no biggy. But when you want to
display the docstrings in an advanced font, like that of an ide with
truetype fonts, formatting gets lost without having the app account
for all the various ways Python coders do their docstrings.

So if you wanted a consistant flexible (really) long term way to
autogenerate and publish your and others code/packages/libraries, it
gets tricky. Ask big-python-library maintainers know, many people go
to chat and forums simply because autogenerated documention wasn't
clear to the non-expert, thus repeating the same questions over and
over. AND perhaps in the beginning it was well documented but since
new constructs and refactoring of code, often auto-generated
documentation can get "reduced" to something unuseful to those not-in-
the-know.

If whitespace indentation is used to define some construct of a
programming language, then how people like to document their code (by
using various forms of whitespace) could impact how well -some- people
learn the new language. Auto-generated documention could very well be
influenced by that decision.

What form of whitespace indentation could effect readability/
understandable code.
For example reducing indentation to 2 spaces instead of 4 might
encourage some coders to use even deeper indentation because the code
could fix more stuff (it's not being used up by whitespace
indentation). Many feel that's a bad thing (I do too).
(not knowing Unit code; I'll use Python)

class Wow(object):
def myfunc(self):
a = func()
if a:
small_indent = something()
if small_indent:
getting_silly = godeeper()
while getting_silly > a:
bet_you_get_the_point += getting_silly -
code_makes_no_sense()
for i in range(100:
if bet_you_get_the_point in SOMEGLOBAL['part1'][0]:
display(a, small_indent, getting_silly,
bet_you_get_the_point)

Well, that may be a little hyperbolic.
But with 2 spaces you can encourage coders to get very deep,
indentially, and still fit 80 chars.
(newly invented word: indentially. But I don't care, you get the
point.)

To me, each viewer of that code should be able to put the indent to
something that fits their taste. And lets face it. most source code
today is viewed in some gui text editor that can reinterpret that
indent to whatever, without generating interperter indentation errors
later. The only exception to consistancy would again be docstrings or
more precisely string blocks, or block strings, or tripe quoted,
whatever you want to call them.

My words are not meant to garner flames or anything, just to cause
thought;
 
S

Steven D'Aprano

On Thu, 01 Dec 2011 10:03:53 -0800, DevPlayer wrote:

[...]
Well, that may be a little hyperbolic. But with 2 spaces you can
encourage coders to get very deep, indentially, and still fit 80 chars.

Why would you want to encourage coders to write deeply indented code?

In my opinion, if your code is indented four or more levels, you should
start to think about refactorising your code; if you reach six levels,
your code is probably a mess.

class K:
def spam():
if x:
for a in b:
# This is about as deep as comfortable
while y:
# Code is starting to smell
try:
# Code smell is now beginning to reek
with z as c:
# And now more of a stench
try:
# A burning, painful stench
if d:
# Help! I can't breathe!!!
for e in f:
# WTF are you thinking?
try:
# DIE YOU M***********ER!!!
while g:
# gibbers quietly
...


The beauty of languages like Python where indentation is significant is
that you can't hide from the ugliness of this code.

class K: {
# Code looks okay to a casual glance.
def spam():{
if x: { for a in b:{
while y:{ try:{ with z as c:{
try:{ if d:{ for e in f:{ try:{
while g:{ ... }}}}
}}}}
}}}}

Deeply indented code *is* painful, it should *look* painful.
 
C

Chris Angelico

Why would you want to encourage coders to write deeply indented code?

In my opinion, if your code is indented four or more levels, you should
start to think about refactorising your code; if you reach six levels,
your code is probably a mess.

So... would it be a bad thing to wrap up all my code into a single
massive expression that returns a single integer for success/failure?
Oh wait, the only time I ever saw code do that was in the IOCCC.
Still, it WAS pretty awesome code!

IOCCC is a code perfume factory. Cloying smell.

ChrisA
 
S

Sells, Fred

Steven, that's probably the most elegant explanation of the "pythonic"
way I've ever seen. I'm saving it for the next time upper management
want to use Java again.

-----Original Message-----
From: [email protected]
[mailto:p[email protected]] On
Behalf Of Steven D'Aprano
Sent: Thursday, December 01, 2011 7:43 PM
To: (e-mail address removed)
Subject: Re: Using the Python Interpreter as a Reference

On Thu, 01 Dec 2011 10:03:53 -0800, DevPlayer wrote:

[...]
Well, that may be a little hyperbolic. But with 2 spaces you can
encourage coders to get very deep, indentially, and still fit 80
chars.

Why would you want to encourage coders to write deeply indented code?

In my opinion, if your code is indented four or more levels, you should
start to think about refactorising your code; if you reach six levels,
your code is probably a mess.

class K:
def spam():
if x:
for a in b:
# This is about as deep as comfortable
while y:
# Code is starting to smell
try:
# Code smell is now beginning to reek
with z as c:
# And now more of a stench
try:
# A burning, painful stench
if d:
# Help! I can't breathe!!!
for e in f:
# WTF are you thinking?
try:
# DIE YOU M***********ER!!!
while g:
# gibbers quietly
...


The beauty of languages like Python where indentation is significant is
that you can't hide from the ugliness of this code.

class K: {
# Code looks okay to a casual glance.
def spam():{
if x: { for a in b:{
while y:{ try:{ with z as c:{
try:{ if d:{ for e in f:{ try:{
while g:{ ... }}}}
}}}}
}}}}

Deeply indented code *is* painful, it should *look* painful.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,069
Latest member
SimplyleanKetoReviews

Latest Threads

Top