Re: comments on Python

Guido van Rossum (Guido.van.Rossum@cwi.nl)
Sat, 23 Nov 91 17:29:57 +0100

[Here's my reply to Bakul. ">>" is me, ">" is Bakul, plain is me again.
We begin with some boring details... --Guido]

>> I'll try. Is there some predefined symbol by which I can recognize
>> sunos-3 from SunOS 4?
>
>I just added #ifdef sun, which is defined. I don't know if sunOS 4
>adds another define to distinguish it from earlier versions.

I don't know either. Anybody else on the list know how ti distinguish
SunOS 4.x from 3.x?

>> When I print it the pages are numbered. Maybe you should shorten the
>> page height in "myformat.sty" -- I set it for European paper size,
>> which is about 12 inches high, while yours is likely to be 11 inches.
>
>Ah, that explains it. Would be nice if your style worked for
>either size (may be we need a4.sty).

There are some comments in the style file that explain how to patch it for
US size paper. Maybe I should distribute it with US size paper turned on
by default.

>> Actually, Python lacks explicit declarations as well -- and indeed it
>
>True. I was just adding up perl's sins! It seems funny that you
>have to import definitions but not declare variable! Even a `def
><var>' will help. I would also like `def <var> <type>' or
>something similar.

I don't believe explicit declarations of local variables is a good idea
for a language intended for casual programming, like Python. Instead, a
compile-time checker should be written that detects use of undefined
variables orq assignment to variables that are never used. Remember, *use*
of an undefined variable is a run-time error in Python -- in a sense, the
assignment that gives the variable a value is its declaration.

Importing definitions (modules) is the equivalent of assigning a value to
a variable, not of declaring a variable. Hence there is no inconsistency.

>> Python on purpose gives you one way to do most things (one way for
>> each things, not one way for all things together!), on the account
>> that it makes the choice easier, and makes programs more readable --
>
>Perl does go overboard in the number of choices it provides but
>common idioms can become easier to read if they have a special
>form. Even though x[i*j] += y is equiv. to x[i*j] = x[i*j] + y, I
>favor the first form. And the same is true of other idioms. So
>`only one way' seems limiting.

Sure. I'm not using this rule to make Python the absolutely smallest
language possible. I just prefer to show people that there is already a
way to do what they want (if this is so) rather than adding yet another
feature. There are actually pretty good reasons to include assignment
operators like "+=" and I'd like to add them.

>> There is a demo directory in the distribution which tries to give the
>> examples, and part of the library is also intended as such -- but more
>> examples always help.
>
>You may also want to post new useful scripts to lang.misc to
>stimulate discussion (and may be flames. But we can ignore those)
>and to give people an opportunity to see python in action.
>(Mailing lists tend to be overwhelming for beginners).

I tried this long ago, but stopped because there seemed too little
interest. Also, it is hard to write good examples that are also useful:
most code either is useful but not written in the absolutely cleanest way
possible, or it is really clean and easy to follow, but lacks useful
options. Maybe someone could go through the demo directory, pick a few
examples that are clean enough to show to outsiders, and post them...

>> >I should be able to say
>> > result += b
>> >or better still,
>> > result += [a,b,c]
>>
>> The latter should automatically work if we let x += y be syntactic
>> sugar for x = x+y. Note that result = result + [x] has a different
>> meaning than result.append(x)...
>
>I understand the difference -- that is why I think overloading
>operators is worth considering. The '+' in result += b is a
>different operator from 'result + [a,b,c]'. As long as the type
>signature is different, there should not be a problem in resolving
>operators, right?

Unfortunately, this would require deferral of operator resolution to
run-time, and could cause quite a few surprises. Consider the following
example. Let's say we have a function to add an element to a list if it
is not already in the list (this could be part of a package emulating set
semantics using lists):

def add_elem(set, elem):
if elem not in set:
set += elem

Normally, the last line would be interpreted (using your operating
overloading) as set.append(elem). However, if we had a set of lists, or a
set of sets (quite a common construct in mathematics; lists of lists are
also very useful in Python), it would be interpreted as "set = set +
elem"! In a language with static typing, this cannot occur, but Python has
very dynamic typing... Changing that would make it an entirely different
language.

>> For simple cases you can use tuples -- this keeps values together but
>> you reference them by position. For larger cases you indeed have to
>> use classes -- but what's ugly about that?
>
>Because all I want is to name tuple constituents. A class is a
>much heavier weight feature. I think what is lacking is *syntax*
>as in a referentially transparent language you can easily translate
>tuple.field to tuple.position. I suppose you do need declarations.

I'm still not convinced that it is necessary to this to the language.
Because of the dynamic typing, the translation of tuple.field to
tuple[position] has to be done at run-time. The implementation of class
instances already provides such a mapping (using a dictionary). Why do
you think classes are heavy-weight? All you need is to place

class Struct(): pass

somewhere early in your module, and then you can create structures using

x = struct()

and fill them with statements like

x.width = 14
x.height = 200

>> You can do this! If a is a list of three elements, just write
>> [x, y, z] = a
>
>Good! Guess I should reread the tutorial!

I'm not absolutely sure it's in there (the tuturial is already
overloaded). It will be in the reference manual I'm writing.

>> import posix, string
>> pipe = posix.popen('ls -l', 'r')
>> for line in pipe.readlines():
>> if line[:5] = 'total': continue
>> [perm,links,user,group,size,mon,day,YoT,name] = string.split(line)[:9]
>> print size, '\t' + name
>
>This is exactly the kind of thing that will let people compare
>python with other languages. Shouldn't that `string.split' be
>`line.split'? Why is '\t' + name preferable to '\t', name?

No it's definitely "string.split(line)". The point is, for better or for
worse, strings don't have attributes, so all string operations that aren't
built-in operations (like "+" for concatenation) have to be functions.
The module "string" is a collection of such functions.

I wrote '\t' + name because '\t', name inserts an extra space between the
tab and the name (print *always* inserts spaces between output items,
except if an item ends in '\n').

>> 'total', which makes this kind of scripts so dangerously non-portable.
>
>Though that does not depend on the scripting language.

It does, because sime scripting languages offer no alternative (e.g., in
"sh" scripts or awk, you just have to parse "ls" output for this case,
while Perl and Python also offer a direct interface to the stat() system
call.

>> There's already a built-in module 'regexp', which does what you want.
>> Access is slightly clumsier than Perl (there's no special syntax to
>> handle regular expressions) and the expressions are simpler (just
>> Henry Spencer's regexp package), but what you want is there...
>
>I should really get reacquainted with python. It has been while
>and my short term memory is getting worse:-(

Go ahead -- the more you use it, the more you'll like it!

>- -- bakul
>
>PS: one more comment. The fact that for built in things you can
>use unqualfied procedures (operators?) such as `len(string)' but
>for user defined class instances you have to do `foo.len()' seems
>inconsistent -- I don't know what can be done though.

len() is a border case: it applies to several different types (all
sequence and dictionary types), some of which currently have no methods
(strings and tuples). I think len(str) is prettier than str.len(), but
this isn't a very important reason. On the other hand, a limited number
of unqualified built-in functions is probably necessary -- would you
prefer to write (x + 1).abs() rather than abs(x + 1) ???

In any case, this is only done for the most important built-in things.
Other built-in functionality is accessed using imported (built-in)
modules, but some things just need to be available at all times. The
alternative, which I consider to be worse, would be to turn them all into
keywords. The "raise" statement is a border case: I played with the idea
of making it a built-in function. However, making it a statement puts it
on the same level as "return", "break" and "continue", which also
unconditionally pass control to some outer level. With "raise" being a
statement, it can profit when the syntax is tightened to disallow code
following such branching statements. Emacs Python mode should
automatically dedent after one of these (it doesn't yet -- anyone care
enough to patch it?)

--Guido van Rossum, CWI, Amsterdam <guido@cwi.nl>
Honary Member, Royal Society for Putting Things on Top of Other Things