Mailing List Archive

Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.)
On 21 Jul 1999, Markus Kohler wrote:
> "Tim Peters" <tim_one@email.msn.com> writes:
>
> > [Tim]
> > > for i in xrange(10000000):
> > > pass
> > > [and RC vs GC implications]
> >
> > [Markus Kohler]
> > > True.
> > > IMHO this is one of Pythons major design flaws.
> >
> > What, specifically?
>
> That flaw is that loops are not implemented using closures.

Sorry, how would that help?

> Instead as far as I understand loops in Python are implemented such that
> the loop counter is created and destroyed for each step of the loop.
>
> You could compare this to tail recursive versus non-tail recursive functions.
>
> Also closures make the implementation of efficient loops more
> difficult they have the advantage that loops and other control
> structures can be better integrated into the OO concept. Smalltalk for
> example doesn't need Iterators for that reason.

Python is not a functional programming language. As I understand it, you
can't really have convenient closures because it is not lexically scoped
(I can give you inconvenient closures...) and there were lengthy
discussions about that some months back. I didn't follow it too closely
because I didn't know what lexically scoped meant then, but the upshot was
(I think) that lexical scoping isn't really the "Python way".

Python isn't really an OO language either, in the sense of something like
Smalltalk or Eiffel.

I have heard it said that Python is a language that "gets it's compromises
exactly right" and that about sums it up for me.

> Lately ee have had already some examples in this group where loop
> overhead was a major factor.

Really? When? Sorry, I don't want to sound disbelieving, but I don't
remember that.

> I measured different kind of loops and
> even the more general while loop was faster in squeak than anything
> else in python.

Python, as I said, is neither functional nor purely OO; it's not
particularly fast either. Fast enough, generally.

> Functions calls seems also to be much slower in Python ...

*That* I believe. Not clear what to do about it though.

> Another problem with loops could be reference counting. I'm wondering
> how often a reference count get's changed when running a loop ...

Not vastly more often than in regular code, I'd guess. It's true that
executing

1+1

spends longer twiddling refcounts than doing the work, but that's Python.

I can't decide which Peters-style ending I want here, so you're all
getting two:

not-OO-functional-or-fast-but-still-great-ly y'rs
it's-not-OO-or-functional-it's-Python-ly y'rs

Michael
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
[Michael Hudson]
> ...
> Python is not a functional programming language.

NOW they tell me <wink>.

> As I understand it, you can't really have convenient closures because it
> is not lexically scoped (I can give you inconvenient closures...) and
> there were lengthy discussions about that some months back. I didn't
> follow it too closely because I didn't know what lexically scoped meant
> then, but the upshot was (I think) that lexical scoping isn't really
> the "Python way".

It wasn't, but it may be. Python's 3-level scoping system (which Guido
routinely calls a 2-level system these days -- I guess because he thinks 2
sounds less contrived than 3 <wink>) was a thoroughly deliberate decision.
Today he'll tell you that he may have overreacted against the rampant abuse
of deep procedure nesting common in large Pascal programs of that long-ago
time. I tangled with him on this in email at the time, but having also
suffered the Pascal abuses, reluctantly agreed to stop harassing him about
it and just see how the 3-level scheme worked out in practice.

I think it worked out great! I was surprised. But there were two miserable
problems:

1) Despite its simplicity, the implementation of name resolution was much
slower than in most languages that support arbitrarily deep lexical nesting.
By far the worst of this got repaired by assigning locals to fixed slots
(and bytecodehacks wouldn't be nearly as much fun without that to abuse
<wink>).

2) Despite that scoping is 3-level, the *syntax* allows nesting functions &
classes to any level. This is an eternal source of confusion for people
coming from other languages, and can take a long time to stop tripping over.
So why did the syntax allow it? Because it would have complicated the
grammar to stop it! Guido may deny that today, but it's the truth <wink>.

Times are different now. The only people *likely* to abuse lexical nesting
these days are Scheme/Lisp heads, but Python's lack of a macro system will
drive them away anyway <wink>.

As far as the implementation goes, arbitrarily deep lexical closures with
indefinite extent are easy in Python -- it's a small & simple patch
(frames-- activation records --are heap-allocated anyway; all that's really
missing is a "static link" to crawl up the lexical nest). Guido even
implemented (but never released) it a few years ago. An unexpected
technical glitch killed it: it turned out that the natural implementation
created cyclic implementation structures that refcounting isn't strong
enough to clean up. Presumably Python2 could repair that by hook or by
crook.

So Schemish lexical scoping may yet become The Python Way! I wouldn't count
on it, though; and maintaining state via class instances will always be more
Pythonic.

[prematurely wise comments elided]

> not-OO-functional-or-fast-but-still-great-ly y'rs
> it's-not-OO-or-functional-it's-Python-ly y'rs

it's-guido's-way-or-the-highway-ly y'rs - tim
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Michael Hudson <mwh21@cam.ac.uk> writes:

> On 21 Jul 1999, Markus Kohler wrote:
> > "Tim Peters" <tim_one@email.msn.com> writes:
> >
> > > [Tim]
> > > > for i in xrange(10000000):
> > > > pass
> > > > [and RC vs GC implications]
> > >
> > > [Markus Kohler]
> > > > True.
> > > > IMHO this is one of Pythons major design flaws.
> > >
> > > What, specifically?
> >
> > That flaw is that loops are not implemented using closures.
>
> Sorry, how would that help?

It wouldn't help regarding performance, but increase the
expressiveness of the language.

>
> > Instead as far as I understand loops in Python are implemented such that
> > the loop counter is created and destroyed for each step of the loop.
> >
> > You could compare this to tail recursive versus non-tail recursive functions.
> >
> > Also closures make the implementation of efficient loops more
> > difficult they have the advantage that loops and other control
> > structures can be better integrated into the OO concept. Smalltalk for
> > example doesn't need Iterators for that reason.
>
> Python is not a functional programming language.

It could be extended by some functional features.
All I want is the integration of loops into the OO concept of the language.

Loops are cannot be used as any other polymorph
function if you don't implement them with closures (please tell me
if there's another way).

Smalltalk Example

iterate over a container and do something for each element looks like this:

aContainer do:[:each | each doSomething]

because do: is just a method like any other method you can redefine it for each
class.
This is very usefull because it allows to for example to loop over a Container
that contains two other Containers ("a" and "b" of an unknown type very easily:

do: aBlock
a do: aBlock.
b do: aBlick.


> As I understand it, you
> can't really have convenient closures because it is not lexically scoped
> (I can give you inconvenient closures...) and there were lengthy
> discussions about that some months back. I didn't follow it too closely
> because I didn't know what lexically scoped meant then, but the upshot was
> (I think) that lexical scoping isn't really the "Python way".
>
> Python isn't really an OO language either, in the sense of something like
> Smalltalk or Eiffel.

IMHO it's very close to Smalltalk, also Guido probably wouldn't agree with me ...
And It has all essential OO features.


The features that make it very similiar to Smalltalk are :
byte code interpreter,
all data are objects (is that really true ?),
crossplatform,
reflection api,
dynamically type checked,

In fact I cannot remember any successfull language that is closer to
Smalltalk than Python is.


>
> I have heard it said that Python is a language that "gets it's compromises
> exactly right" and that about sums it up for me.

I also like some things about Python. For example the module system, and how
easily external C functions can be integrated.

>
> > Lately ee have had already some examples in this group where loop
> > overhead was a major factor.
>
> Really? When? Sorry, I don't want to sound disbelieving, but I don't
> remember that.

It was about reading a file and put the words into some hash table.
As far as I can remember to loop overhead was a dominating factor.
And Python was much slower than perl for example.

>
> > I measured different kind of loops and
> > even the more general while loop was faster in squeak than anything
> > else in python.
>
> Python, as I said, is neither functional nor purely OO;

Ok it's not purely OO because you can define global functions.
But it's anything else is pretty much OO.

> it's not
> particularly fast either. Fast enough, generally.
>
> > Functions calls seems also to be much slower in Python ...
>
> *That* I believe. Not clear what to do about it though.

It's IMHO the overly complex function call mechanism, with it's
default values on all that other stuff. I really can imagine it's difficult to
make this fast. IMHO it's not worth the effort and maybe one should
invent Python lite that uses a simpler call mechanism :-O

>
> > Another problem with loops could be reference counting. I'm wondering
> > how often a reference count get's changed when running a loop ...
>
> Not vastly more often than in regular code, I'd guess. It's true that
> executing
>
> 1+1
>
> spends longer twiddling refcounts than doing the work, but that's Python.
>
> I can't decide which Peters-style ending I want here, so you're all
> getting two:
>
> not-OO-functional-or-fast-but-still-great-ly y'rs
> it's-not-OO-or-functional-it's-Python-ly y'rs
>


Markus
--
Markus Kohler mailto:markus_kohler@hp.com
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
On 22 Jul 1999 13:32:55 +0200, Markus Kohler <markusk@bidra241.bbn.hp.com>
wrote:

> IMHO it's very close to Smalltalk, also Guido probably wouldn't agree with me ...
> And It has all essential OO features.
>
>
> The features that make it very similiar to Smalltalk are :
> byte code interpreter,
> all data are objects (is that really true ?),
> crossplatform,
> reflection api,
> dynamically type checked,

One problem though with Python is the fact that it does make a distinction
between types and classes. Another is the garbage collection scheme that's
using.

> In fact I cannot remember any successfull language that is closer to
> Smalltalk than Python is.

Objective-C. Is a dynamically typed language and is compiled.


Greetings,
--
Ovidiu Predescu <ovidiu@cup.hp.com>
http://andromeda.cup.hp.com/ (inside HP's firewall only)
http://www.geocities.com/SiliconValley/Monitor/7464/
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Tim Peters wrote:
>
> I think it worked out great! I was surprised.

I wouldn't be quite so enthusiastic. I would say that
one can learn to live with the inconvenience, and
even almost forget that it's there most of the time.
But I still feel annoyed whenever I bump up against
it.

> and maintaining state via class instances will always be more
> Pythonic.

I don't think you can assert that until a Python
with lexical scoping has been in use for a while
and we see how people prefer to write things.
My bet is that a lot of things we write now like

b = Button(..., command = lambda self=self: self.blat(42))

would get written as

b = Button(..., command = lambda: self.blat(42))

and we would all wonder why we didn't storm
Guido's palace years ago and force him to release
his lexical scoping code at gunpoint...

Greg
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Markus Kohler <markusk@bidra241.bbn.hp.com> wrote:
> Michael Hudson <mwh21@cam.ac.uk> writes:
>> On 21 Jul 1999, Markus Kohler wrote:
>> > Lately ee have had already some examples in this group where loop
>> > overhead was a major factor.
>>
>> Really? When? Sorry, I don't want to sound disbelieving, but I don't
>> remember that.

> It was about reading a file and put the words into some hash table.
> As far as I can remember to loop overhead was a dominating factor.
> And Python was much slower than perl for example.

Well, if I remember correctly, eventually the perl version was slower
then the python optimized version:) The point was that reading bytes is
*much* slower then reading large chunks of data. So it had to do with
disk IO and not looping. Atleast that's what I remember from that thread.
(I checked with deja-news and low and behold I'm right! that is if we
refer to the same thread titled 'Speed of python' way back in feb:)

--
groetjes, carel
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Sorry my Smalltalk example is wrong.
I must have coded for to long in this poor language called C ...
I must look like this :


do: aBlock
a do:[:each | aBlock value: each]
b do:[:each | aBlock value: each]

more complicated but still very easy to understand.

Greetings,
Markus
--
Markus Kohler mailto:markus_kohler@hp.com
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Markus Kohler wrote:
>
> Sorry my Smalltalk example is wrong.
> I must have coded for to long in this poor language called C ...
> I must look like this :
>
> do: aBlock
> a do:[:each | aBlock value: each]
> b do:[:each | aBlock value: each]
>
> more complicated but still very easy to understand.

No, your original code was fine:

do: aBlock
a do: aBlock.
b do: aBlock.

No need to wrap the incoming block in yet another block.

You could also write it as:

do: aBlock
a , b do: aBlock.

which might be even clearer.

-- Tim Olson
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Tim Olson <tim@jumpnet.com> writes:

> Markus Kohler wrote:
> >
> > Sorry my Smalltalk example is wrong.
> > I must have coded for to long in this poor language called C ...
> > I must look like this :
> >
> > do: aBlock
> > a do:[:each | aBlock value: each]
> > b do:[:each | aBlock value: each]
> >
> > more complicated but still very easy to understand.
>
> No, your original code was fine:
>
> do: aBlock
> a do: aBlock.
> b do: aBlock.
>
> No need to wrap the incoming block in yet another block.
>
> You could also write it as:
>
> do: aBlock
> a , b do: aBlock.
>

Ah that's cool,
I didn't have the time to try it out ...
I saw code that used the #value: message
but, of course it has to be only used if you want to do addiotional
things for each element.

It seems to be really time to get back to Smalltalk for me ...

Markus
--
Markus Kohler mailto:markus_kohler@hp.com
Loops and stuff (was Re: Python and Boehm-Demers GC, I have code.) [ In reply to ]
Following up on just a couple points:

[Markus Kohler]
> ...
> IMHO it's [Python] very close to Smalltalk, also Guido probably wouldn't
> agree with me ...
> And It has all essential OO features.

Python is something of an ink blot test that way: people coming from Scheme
think it's very close to that (and just needs macros and continuations and
lexical closures <wink>); people coming from pure functional languages have
a similar tale (and it just needs non-strict functions and a pile of
combinator notation); people coming from Perl -- well, let's stop before it
gets silly <wink>.

Python takes a lot of ideas from a lot of languages, but it has its own
worldview, and its own corresponding implementation. It really isn't "like"
anything else at heart, in philosophy or implementation.

I'm looking forward to the day when I drop in on another comp.lang.* group
and read "you know, this language is very close to Python, and all it really
needs is namespaces modeled as explicit dicts" <wink>.

>>> Lately we have had already some examples in this group where loop
>>> overhead was a major factor.

[Michael Hudson]
>> Really? When? Sorry, I don't want to sound disbelieving, but I don't
>> remember that.

[back to Markus]
> It was about reading a file and put the words into some hash table.
> As far as I can remember to loop overhead was a dominating factor.
> And Python was much slower than perl for example.

Ah, that one. That's not loops. It's input. Line-at-a-time input on my
platform is about 3 times faster in Perl than Python; indeed, it's faster in
Perl than in C! It's not loop mechanisms or even refcounting "to blame"
here (btw, Perl does refcounting too ...). It's that Perl breaks into the
stdio abstraction, going under the covers in platform + compiler specific
ways, peeking and poking C stdio FILE structs directly.

Very clever, but a lot of work. Most fgets implementations suck, and Perl
deserves all the credit for not settling for that. I doubt Python will do
it too, not as a matter of principle, but because nobody capable of it will
make time to do it.

would-rather-have-faster-functions-myself-but-if-wishes-were-bananas-
we'd-be-swimming-in-mushy-fruit-ly y'rs - tim