473,881 Members | 1,721 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Python's biggest compromises

I have been reading a book about the evolution of the Basic
programming language. The author states that Basic - particularly
Microsoft's version is full of compromises which crept in along the
language's 30+ year evolution.

What to you think python largest compromises are?

The three that come to my mind are significant whitespace, dynamic
typing, and that it is interpreted - not compiled. These three put
python under fire and cause some large projects to move off python or
relegate it to prototyping.

Whitespace is an esthetic preference that make Andrew Hunt and David
Thomas (of Pragmatic Programmer fame) prefer Ruby. Personally, I love
it - but I can see why some people might not like it (30 years of
braces).

Dynamic typing causes the most fuss. I like Guido's answer to the
question -
"Doesn't dynamic typing cause more errors to creep into the code because you catch them later than compile time?". "No, we use Unit Testing in Zope".


That said, obvious Basic compromised by using things such as "Option
Explicit", thereby allowing both dynamic and more static style
variables. Yahoo groups moved from python to C due to dynamic typing.

Non-compiled - obviously there are times when performance matters more
than other things. Google I believe uses python to prototype (or used)
and then turns to c++ for heavy lifting.

What about immutable strings? I'm not sure I understand Guido's
preference for them.

Anthony
http://xminc.com/anthony
Jul 18 '05
65 6780
On Thu, 2003-07-31 at 08:55, Anthony_Barker wrote:
The three that come to my mind are significant whitespace, dynamic
typing, and that it is interpreted - not compiled. These three put
python under fire and cause some large projects to move off python or
relegate it to prototyping.


I think these are valid as "compromise s", not to be confused with
flaws. These are all explicit choices, and ones for which the original
justifications remain valid. A lot of stuff in Basic is simply flaws,
or based on justifications that no longer apply to today's programming
world.
Anyway, I might add mine: the nature of modules as executed code is a
compromise. That is, a module isn't a declaration, it's a program to be
executed in its own namespace. When you import a module, you are
executing the module then looking at the namespace.

There are some advantages to this, particularly in the transparency of
the implementation -- things don't always work the way you might want
(e.g., circular imports), but it's usually not that hard to understand
why (and often the way you want things to work has nasty gotchas that
you wouldn't have thought of). It also opens up a lot of possibilities
for dynamicism in class and function declaration, like doing this in the
top level:

if something:
def func(x): ...
else:
def func(x): ...

But it's a compromise, because it makes things more difficult as well.
It's a *big* problem in any long-running process, where you may want to
modify code underlying the system without rebuilding the entire state.
Classes aren't declared, they are simply constructed, so by reloading a
module all the persistent instances still exist and refer to the defunct
class. You can modify classes at runtime, but this is different from
simply rerunning the class definition. (A clever metaclass *could* make
those equivalent, though... hmmm...)

A related problem is that Python objects generally can accept any
instance variable names, and names are not declared anywhere. Again,
this makes it difficult to deal with long-lived objects. If you change
the class so that all instances get a new attribute, old objects won't
be updated. I'm thinking about both of these things in terms of
Smalltalk, where they make tools possible that really add to the ease of
developing in its environment.

Not that I don't like the fun tricks Python lets you do. Prototype-like
programming (as in Self) is very accessible in Python, and classes are
only a suggestion not a dominant concept. So, it's a compromise.

There are lots and lots of compromises in Python -- every aspect has
pluses and minuses to it. Personally I like whitespace sensitivity well
enough, but in the larger sense I think it probably was the wrong choice
-- but that's based on how I weigh various benefits and problems, and
other people will validly weigh them differently.

Ian

Jul 18 '05 #11

"Robin Becker" <ro***@jessikat .fsnet.co.uk> wrote in message
news:TB******** ******@jessikat .fsnet.co.uk...
In article <vi************ @news.supernews .com>, John Roth
<ne********@jhr othjr.com> writes
.....
High performance isn't Python's target. If PyPy ever gets their act
off the ground, then we will have a shot at a good quality JIT
interpreter. Then watch it fly.

.... doesn't psyco already attempt to do JIT? It certainly doesn't
speed things up that much. If all the variables are known to be of a
specific type then you could expect C like speeds from a good JIT, but
without global analysis it's hard to see how we infer/guarantee python
types.


Well, that's certainly a problem, but Bicycle Repair Man seems to
do a pretty good job of type inference, at least for refactoring.

One of the things to consider here is that a decent JIT interpreter
would automatically change the playing field for what is good
practice and what isn't, at least if you expect performance.

John Roth --
Robin Becker

Jul 18 '05 #12
On Thu, 2003-07-31 at 16:27, John Roth wrote:
"Robin Becker" <ro***@jessikat .fsnet.co.uk> wrote in message
news:TB******** ******@jessikat .fsnet.co.uk...
In article <vi************ @news.supernews .com>, John Roth
<ne********@jhr othjr.com> writes

.....
High performance isn't Python's target. If PyPy ever gets their act
off the ground, then we will have a shot at a good quality JIT
interpreter. Then watch it fly.

.... doesn't psyco already attempt to do JIT? It certainly doesn't
speed things up that much. If all the variables are known to be of a
specific type then you could expect C like speeds from a good JIT, but
without global analysis it's hard to see how we infer/guarantee python
types.


Well, that's certainly a problem, but Bicycle Repair Man seems to
do a pretty good job of type inference, at least for refactoring.


And Java's JIT is based on (at least originally) work done on Self,
which had to do type inference. And actually in many circumstances Java
requires type inference, because you can substitute in an instance of a
subclass.

Anyway, JIT is all about runtime analysis -- if you could infer types
completely before running the program, you would just put in the
optimizations statically (i.e., compiling optimizations). JIT does
those optimizations at runtime by definition.

And Bicycle Repair Man is inspired by the Refactoring Browser, an IDE
tool based on another dynamic language (Smalltalk), not on a tool from a
static language (like Java).

Ian

Jul 18 '05 #13
an************@ hotmail.com (Anthony_Barker ) wrote in message news:<89******* *************** ***@posting.goo gle.com>...
What to you think python largest compromises are?


I think reference counting is. Added to this the fact that
garbage collection is also possible (as in Jython). So we get
the worst of both worlds.

1. Idioms like this won't work portably:

def foo():
f = file('x')
return f.read()

Even though f.__del__ closes the file, in garbage
collected environment the f object might not get deleted
in a good while, and would cause problems.

2. And then, we still need to use weakref to ensure
that our crossreferenced stuff works both with and without GC.

Worst of both indeed. Maybe the decision to choose reference
counting was driven by speed considerations. That might've
been reasonable back in early 90's, but GC techniques have
evolved from those days and so GC would be a superior
technique now.

Well, since no one else pointed this out yet, maybe there's
some flaw in my reasoning.
Jul 18 '05 #14
Dennis Lee Bieber:
Whereas BASIC started life as an interpreted language wherein every statement had a line number, conditionals (IF) did jumps to line
numbers, and all variables were global (even across subroutine calls).


Not interpreted.
See http://wombat.doc.ic.ac.uk/foldoc/fo...artmouth+BASIC
] Dartmouth BASIC
] <language> The original BASIC language [...] Unlike most later
] BASIC dialects, Dartmouth BASIC was compiled

or a more detailed description at http://www.kbasic.org/1/history.php3
which says the first interpreted BASIC was the Micro-Soft one for
the Altair.

In more seriousness, compiled v. interpreted is an implementation
detail which has very little impact on the language. The other examples
you gave are more relevant.

One thing to consider is - what's the *compromise* in the different
versions of BASIC? That is, how was the support for backwards-
compatible operations in BASIC (which you list as a compromise)
any different than Python's backwards compatibility support?

Andrew
da***@dalkescie ntific.com
Jul 18 '05 #15
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Anthony_Barker wrote:
| I have been reading a book about the evolution of the Basic
| programming language. The author states that Basic - particularly
| Microsoft's version is full of compromises which crept in along the
| language's 30+ year evolution.
|
| What to you think python largest compromises are?
|
IHMO it is the lambda expression.
These "functions" are not real functions. You can not use
statements in them.

What Python realy needs here is some means to make an expression
from a list of statements (called suite in the syntax defintion).
That given PEP 308 (If-then-else expression) or PEP 318 (Function/Method
Decorator Syntax) are mostly pointless.

Let me give an example:

Suppose there some special braces like (: :) and a exit operator like a
unary ^ one can write a conditional expession like that:
(:
~ if f():
~ ^trueValue
~ else:
~ ^falseValue :)

classmethods can be declared as follows:
cm = (:
~ def im( arg0, arg1 ):
~ return answer
~ ^classmethod( im ) :)

or
cm = classmethod( (:
~ def im( arg0, arg1 ):
~ return answer
~ ^im
~ :) )

obvously this demands for some means to write anonymous functions like

def ( arg0, arg1 ):
~ return arg0 - arg1

semanticly this should transform to

(:
~ def newName( arg0, arg1 ):
~ return arg0 - arg1
~ ^newName :)

giving

cm = def ( arg0, arg1 ):
~ return answer

Ok, I admit that this is difficult to be integrated in
the existing syntax. Perhaps we can not drop the braces
around such expression.

Is this worth writing a PEP?

|
|>"No, we use Unit Testing in Zope".
I am still missing a simple testing framework. doctest
is a good idea, but conflicts with syntax hilighting in most
editors.

|
|
| That said, obvious Basic compromised by using things such as "Option
| Explicit", thereby allowing both dynamic and more static style
| variables. Yahoo groups moved from python to C due to dynamic typing.
This is not a problem. They key to speed is using extension written
in C for performance. Normaly you will find one that sloves your problem.

|
| Non-compiled - obviously there are times when performance matters more
| than other things. Google I believe uses python to prototype (or used)
| and then turns to c++ for heavy lifting.
|
| What about immutable strings? I'm not sure I understand Guido's
| preference for them.
In fact the array module provides mutable strings.

|
| Anthony
| http://xminc.com/anthony

HTH,
Gerald
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)
Comment: Using GnuPG with Debian - http://enigmail.mozdev.org

iD8DBQE/KjWgEDg9cqFA1jQ RAovzAJkBygPzdf HsoVXu9H2QHnxTD 9sMmACdHvY5
dB1j4kXTzejml7f G0oSwhUg=
=WGR+
-----END PGP SIGNATURE-----

Jul 18 '05 #16
In article <ma************ *************** *******@python. org>, Ian
Bicking <ia**@colorstud y.com> writes
And Java's JIT is based on (at least originally) work done on Self,
which had to do type inference. And actually in many circumstances Java
requires type inference, because you can substitute in an instance of a
subclass.

Anyway, JIT is all about runtime analysis -- if you could infer types
completely before running the program, you would just put in the
optimization s statically (i.e., compiling optimizations). JIT does
those optimizations at runtime by definition.

but Java does at least require specifying every type and that must at
least cut down on the amount of work required.
And Bicycle Repair Man is inspired by the Refactoring Browser, an IDE
tool based on another dynamic language (Smalltalk), not on a tool from a
static language (like Java).

Ian


I don't have any data here, but I believe Python is just a little too
weakly typed for compiling to float*float type assembler efficiently.
--
Robin Becker
Jul 18 '05 #17

"Robin Becker" <ro***@jessikat .fsnet.co.uk> wrote in message
news:23******** ******@jessikat .fsnet.co.uk...
In article <ma************ *************** *******@python. org>, Ian
Bicking <ia**@colorstud y.com> writes
And Java's JIT is based on (at least originally) work done on Self,
which had to do type inference. And actually in many circumstances Java
requires type inference, because you can substitute in an instance of a
subclass.

Anyway, JIT is all about runtime analysis -- if you could infer types
completely before running the program, you would just put in the
optimization s statically (i.e., compiling optimizations). JIT does
those optimizations at runtime by definition.

but Java does at least require specifying every type and that must at
least cut down on the amount of work required.
And Bicycle Repair Man is inspired by the Refactoring Browser, an IDE
tool based on another dynamic language (Smalltalk), not on a tool from a
static language (like Java).

Ian


I don't have any data here, but I believe Python is just a little too
weakly typed for compiling to float*float type assembler efficiently.


The trick with JITs is that they don't depend on absolute type
consistency. They depend on the observation that 99.44% of your
code is type consistent, and that consistency will turn up at run time. So
the code they generate depends on that discovered consistency, and
checks in front of each section to discover if the types are what the
code expects.

If it is, they execute it, if it isn't, they abandon it and go back to
the intepreter to discover what happened.

John Roth --
Robin Becker

Jul 18 '05 #18
ha******@yahoo. com.au (Hannu Kankaanpää) writes:
Worst of both indeed. Maybe the decision to choose reference
counting was driven by speed considerations.
Ease of implementation, portability and playing nicely with C
extensions are more likely candidates, IMO.
That might've been reasonable back in early 90's, but GC techniques
have evolved from those days and so GC would be a superior technique
now.


<button nature="hot">
Reference counting *is* a form of garbage collection.
</button>

Saying "Ref. counting sucks, let's use GC instead" is a statement near
as dammit to meaningless.

Given the desires above, I really cannot think of a clearly better GC
strategy for Python that the one currently employed. AFAICS, the
current scheme's biggest drawback is its memory overhead, followed by
the cache-trashing tendencies of decrefs.

What would you use instead?

Cheers,
mwh

--
After a heavy night I travelled on, my face toward home - the comma
being by no means guaranteed. -- paraphrased from cam.misc
Jul 18 '05 #19

"Hannu Kankaanpää" <ha******@yahoo .com.au> wrote in message
news:84******** *************** ***@posting.goo gle.com...
an************@ hotmail.com (Anthony_Barker ) wrote in message

news:<89******* *************** ***@posting.goo gle.com>...
What to you think python largest compromises are?


I think reference counting is. Added to this the fact that
garbage collection is also possible (as in Jython). So we get
the worst of both worlds.

1. Idioms like this won't work portably:

def foo():
f = file('x')
return f.read()

Even though f.__del__ closes the file, in garbage
collected environment the f object might not get deleted
in a good while, and would cause problems.

2. And then, we still need to use weakref to ensure
that our crossreferenced stuff works both with and without GC.

Worst of both indeed. Maybe the decision to choose reference
counting was driven by speed considerations. That might've
been reasonable back in early 90's, but GC techniques have
evolved from those days and so GC would be a superior
technique now.

Well, since no one else pointed this out yet, maybe there's
some flaw in my reasoning.


There's a flaw in your reasoning. The various techniques that
descend from mark and sweep (which is what you're
calling garbage collection) depend on being able to
identify all of the objects pointed to. For objects that are
owned by Python, that's a lengthy (that is, inefficient)
process, and it's not possible in general for objects that
are created by extensions.

Reference counting only depends on having the
object itself, and control of the creation and removal
of references. The latter is a frequent source of bugs
and memory leaks in extensions.

It's easy to say that various languages would be improved
by adding "real" garbage collection, but those techniques
impose significant design constraints on the implementation
model.

John Roth
Jul 18 '05 #20

This thread has been closed and replies have been disabled. Please start a new discussion.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.