A critic of Guido's blog on Python's lambda

A

Alex Martelli

Ken Tilton said:
Looks like dictionaries are no match for the ambiguity of natural
language. :) Let me try again: it is Python itself that cannot scale, as
in gain "new power and capability", and at least in the case of lambda
it seems to be because of indentation-sensitivity.

In my opinion (and that of several others), the best way for Python to
grow in this regard would be to _lose_ lambda altogether, since named
functions are preferable (and it's an acknowledged Python design
principle that there should ideally be just one obvious way to perform a
task); GvR used to hold the same opinion, but changed his mind recently,
alas, so we'll keep the wart.

But, quite apart from the whole issue of whether it's desirable to
languages to change massively ("add new power and capability" meaning
new enriched features in the language itself), your whole argument is
bogus: it's obvious that _any_ fundamental design choice in an artefact
will influence the feasibility and desirability of future design choices
in future releases of that same, identical artefact. At a syntax-sugar
level, for example, Lisp's choice to use parentheses as delimiter means
it's undesirable, even unfeasible, to use the single character '(' as an
ordinary identifier in a future release of the language. Considering
this to mean that Lisp "cannot scale" is just as ridiculous as
considering that Python "cannot scale" by not having an elegant way to
make lambdas heavier and richer -- totally laughable and idiotic. ``An
unneeded feature "cannot" be added (elegantly) in future releases of the
language'' is just as trivial and acceptable for the unneded feature
``allow ( as an ordinary single-character identifier'' as for the
unneded feature ``allow unnamed functions with all the flexibility of
named ones''.
By contrast, in On Lisp we see Graham toss off Prolog in Chapter 22 and

Oh, is that the same Graham who writes:

"""
A friend of mine who knows nearly all the widely used languages uses
Python for most of his projects. He says the main reason is that he
likes the way source code looks. That may seem a frivolous reason to
choose one language over another. But it is not so frivolous as it
sounds: when you program, you spend more time reading code than writing
it. You push blobs of source code around the way a sculptor does blobs
of clay. So a language that makes source code ugly is maddening to an
exacting programmer, as clay full of lumps would be to a sculptor.
"""
....? [[ I suspect that friend is in fact a common friend of mine and
Graham's, the guy you also mention later in your post, and who
introduced Graham and me when G recently came talk at Google (we had
"brushed" before, speaking in the same sessions at conferences and the
like, but had never "met", as in, got introduced and _talked_...;-). ]]

But, no matter, let's get back to Graham's point: significant
indentation is a large part of what gives Python its own special beauty,
uncluttered by unneeded punctuation. And while you, I, Graham, and that
common friend of ours, might likely agree that Lisp, while entirely
different, has its own eerie beauty, most people's aesthetics are poles
apart from that (why else would major pure-FP languages such as *ML and
Haskell entirely reject Lisp's surface syntax, willingly dropping the
ease of macros, to introduce infix operator syntax etc...? obviously,
their designers' aesthetics weigh parenthesized prefixsyntax negatively,
despite said designers' undeniable depth, skill and excellence).


Alex
 
B

Bill Atkins

In my opinion (and that of several others), the best way for Python to
grow in this regard would be to _lose_ lambda altogether, since named
functions are preferable (and it's an acknowledged Python design
principle that there should ideally be just one obvious way to perform a
task); GvR used to hold the same opinion, but changed his mind recently,
alas, so we'll keep the wart.

But, quite apart from the whole issue of whether it's desirable to
languages to change massively ("add new power and capability" meaning
new enriched features in the language itself), your whole argument is
bogus: it's obvious that _any_ fundamental design choice in an artefact
will influence the feasibility and desirability of future design choices
in future releases of that same, identical artefact. At a syntax-sugar
level, for example, Lisp's choice to use parentheses as delimiter means
it's undesirable, even unfeasible, to use the single character '(' as an
ordinary identifier in a future release of the language. Considering
this to mean that Lisp "cannot scale" is just as ridiculous as
considering that Python "cannot scale" by not having an elegant way to
make lambdas heavier and richer -- totally laughable and idiotic. ``An
unneeded feature "cannot" be added (elegantly) in future releases of the
language'' is just as trivial and acceptable for the unneded feature
``allow ( as an ordinary single-character identifier'' as for the
unneded feature ``allow unnamed functions with all the flexibility of
named ones''.

Not so infeasible:

(let ((|bizarrely(named()symbol| 3))
(+ |bizarrely(named()symbol| 4))

;; => 7

And in any case, enforced indentation is a policy with vastly more
serious consequences than the naming of identifiers.
By contrast, in On Lisp we see Graham toss off Prolog in Chapter 22 and

Oh, is that the same Graham who writes:

"""
A friend of mine who knows nearly all the widely used languages uses
Python for most of his projects. He says the main reason is that he
likes the way source code looks. That may seem a frivolous reason to
choose one language over another. But it is not so frivolous as it
sounds: when you program, you spend more time reading code than writing
it. You push blobs of source code around the way a sculptor does blobs
of clay. So a language that makes source code ugly is maddening to an
exacting programmer, as clay full of lumps would be to a sculptor.
"""
...? [[ I suspect that friend is in fact a common friend of mine and
Graham's, the guy you also mention later in your post, and who
introduced Graham and me when G recently came talk at Google (we had
"brushed" before, speaking in the same sessions at conferences and the
like, but had never "met", as in, got introduced and _talked_...;-). ]]

But, no matter, let's get back to Graham's point: significant
indentation is a large part of what gives Python its own special beauty,
uncluttered by unneeded punctuation. And while you, I, Graham, and that
common friend of ours, might likely agree that Lisp, while entirely
different, has its own eerie beauty, most people's aesthetics are poles
apart from that (why else would major pure-FP languages such as *ML and
Haskell entirely reject Lisp's surface syntax, willingly dropping the
ease of macros, to introduce infix operator syntax etc...? obviously,
their designers' aesthetics weigh parenthesized prefixsyntax negatively,
despite said designers' undeniable depth, skill and excellence).


Alex
 
K

Ken Tilton

Alex said:
In my opinion (and that of several others), the best way for Python to
grow in this regard would be to _lose_ lambda altogether, since named
functions are preferable (and it's an acknowledged Python design
principle that there should ideally be just one obvious way to perform a
task); GvR used to hold the same opinion, but changed his mind recently,
alas, so we'll keep the wart.

Yes, I am enjoying watching lambda teetering on the brink. So it has
been re-upped for another tour? Go, lambda! Go, lambda!
But, quite apart from the whole issue of whether it's desirable to
languages to change massively ("add new power and capability" meaning
new enriched features in the language itself), your whole argument is
bogus: it's obvious that _any_ fundamental design choice in an artefact
will influence the feasibility and desirability of future design choices
in future releases of that same, identical artefact.

True but circular, because my very point is that () was a great design
choice in that it made macros possible and they made CL almost
infinitely extensible, while indentation-sensitivity was a mistaken
design choice because it makes for very clean code (I agree
wholeheartedly) but placed a ceiling on its expressiveness.

As for:
At a syntax-sugar
level, for example, Lisp's choice to use parentheses as delimiter means
it's undesirable, even unfeasible, to use the single character '(' as an
ordinary identifier in a future release of the language.

(defun |(| (aside) (format nil "Parenthetically speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parenthetically speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?
Considering
this to mean that Lisp "cannot scale" is just as ridiculous as
considering that Python "cannot scale" by not having an elegant way to
make lambdas heavier and richer -- totally laughable and idiotic.

Harsh. :) I demand satisfaction. See end of article.
``An
unneeded feature "cannot" be added (elegantly) in future releases of the
language'' is just as trivial and acceptable for the unneded feature
``allow ( as an ordinary single-character identifier'' as for the
unneded feature ``allow unnamed functions with all the flexibility of
named ones''.




Oh, is that the same Graham who writes:

So we are going to skip the point I was making about Common Lisp being
so insanely extensible? By /application/ programmers? Hell, for all we
know CL does have a BDFL, we just do not need their cooperation.
"""
A friend of mine who knows nearly all the widely used languages uses
Python for most of his projects. He says the main reason is that he
likes the way source code looks.

No argument. The little Python I wrote while porting Cells to Python was
strikingly attractive. But it was a deal with the devil, unless Python
is content to be just a scripting language. (And it should be.)

OK, I propose a duel. We'll co-mentor this:

http://www.lispnyc.org/wiki.clp?page=PyCells

In the end Python will have a Silver Bullet, and only the syntax will
differ, because Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.

Then we can just eyeball the code and see if the difference is
interesting. These abstract discussions do tend to loop.

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 
A

Alex Martelli

Bill Atkins said:
Not so infeasible:

(let ((|bizarrely(named()symbol| 3))
(+ |bizarrely(named()symbol| 4))

;; => 7

Read again what I wrote: I very specifically said "ordinary
*single-character* identifier" (as opposed to "one of many characters
inside a multi-character identifier"). Why do you think I said
otherwise, when you just quoted what I had written? (Even just a
_leading_ ( at the start of an identifier may be problematic -- and just
as trivial as having to give names to functions, of course, see below).

And in any case, enforced indentation is a policy with vastly more
serious consequences than the naming of identifiers.

So far, what was being discussed here isn't -- having to use an
identifier for an object, rather than keeping it anonymous -- trivial.
Python practically enforces names for several kinds of objects, such as
classes and modules as well as functions ("practically" because you CAN
call new.function(...), type(...), etc, where the name is still there
but might e.g. be empty -- not a very practical alternative, though) --
so what? Can you have an unnamed macro in Lisp? Is being "forced" to
name it a "serious consequence"? Pah.

Anyway, I repeat: *any* design choice (in a language, or for that matter
any other artefact) has consequences. As Paul Graham quotes and
supports his unnamed friend as saying, Python lets you easily write code
that *looks* good, and, as Graham argues, that's an important issue --
and, please note, a crucial consequence of using significant
indentation. Alien whitespace eating nanoviruses are no more of a worry
than alien parentheses eating nanoviruses, after all.


Alex
 
B

Bill Atkins

Read again what I wrote: I very specifically said "ordinary
*single-character* identifier" (as opposed to "one of many characters
inside a multi-character identifier"). Why do you think I said
otherwise, when you just quoted what I had written? (Even just a
_leading_ ( at the start of an identifier may be problematic -- and just
as trivial as having to give names to functions, of course, see below).

Well, the same technique can obviously be used for:

(let ((|(| 3)))
(+ |(| 4)))
;; => 7

The length of the identifier is irrelevant...
So far, what was being discussed here isn't -- having to use an
identifier for an object, rather than keeping it anonymous -- trivial.
Python practically enforces names for several kinds of objects, such as
classes and modules as well as functions ("practically" because you CAN
call new.function(...), type(...), etc, where the name is still there
but might e.g. be empty -- not a very practical alternative, though) --
so what? Can you have an unnamed macro in Lisp? Is being "forced" to
name it a "serious consequence"? Pah.

Common Lisp does not support unnamed macros (how would these be
useful?), but nothing stops me from adding these. What use case do
you envision for anonymous macros?
Anyway, I repeat: *any* design choice (in a language, or for that matter
any other artefact) has consequences. As Paul Graham quotes and
supports his unnamed friend as saying, Python lets you easily write code
that *looks* good, and, as Graham argues, that's an important issue --
and, please note, a crucial consequence of using significant
indentation. Alien whitespace eating nanoviruses are no more of a worry
than alien parentheses eating nanoviruses, after all.

It *is* an important issue, but it's also a subjective issue. I find
Lisp to be far prettier than any syntax-based language, so it's far
from an objective truth that Python code often looks good - or even at
all.

Plus, I can easily write code that looks good without using a language
that enforces indentation rules. Lisp's regular syntax lets Emacs do
it for me with a simple C-M-a C-M-q. What could be easier?
 
A

Alex Martelli

Ken Tilton said:
True but circular, because my very point is that () was a great design
choice in that it made macros possible and they made CL almost
infinitely extensible, while indentation-sensitivity was a mistaken
design choice because it makes for very clean code (I agree
wholeheartedly) but placed a ceiling on its expressiveness.

Having to give functions a name places no "ceiling on expressiveness",
any more than, say, having to give _macros_ a name.

As for:


(defun |(| (aside) (format nil "Parenthetically speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parenthetically speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?

Interestingly, the SECOND lisper to prove himself unable to read the
very text he's quoting. Reread carefully, *USE THE ***SINGLE***
CHARACTER* ... *AS AN ORDINARY IDENTIFIER*. What makes you read a
``PART OF'' that I had never written? You've shown how to use the
characters as *PART* of an identifier [[and I believe it couldn't be the
very start]], and you appear to believe that this somehow refutes my
assertion?

Are you ready to admit you were utterly wrong, and (while it is indeed
true that my Lisp is rusty) there is nothing in this exchange to show
it, as opposed to showing rustiness in your ability to understand
English? Or shall we move from polite although total dissent right on
to flamewars and namecalling?

The point is, OF COURSE any design choice places limitations on future
design choices; but some limitations are even DESIRABLE (a language
where *every* single isolated character could mean anything whatsoever
would not be "expressive", but rather totally unreadable) or at least
utterly trivial (syntax-sugar level issues most typically are). Wilfully
distorting some such limitation as meaning that one language "can scale"
(when EVERY language inevitably has SOME such limitations) is not even
funny, and clearly characterizes a polemist who is intent on proving a
preconceived thesis, as opposed to an investigator with any real
interest in ascertaining the truth of the matter.
So we are going to skip the point I was making about Common Lisp being
so insanely extensible? By /application/ programmers? Hell, for all we
know CL does have a BDFL, we just do not need their cooperation.

Yes, we are, because the debate about why it's better for Python (as a
language used in real-world production systems, *SCALABLE* to extremely
large-scale ones) to *NOT* be insanely extensible and mutable is a
separate one -- Python's uniformity of style allows SCALABILITY of
teams, and teams-of-teams, which is as crucial in the real world as
obviously not understood by you (the law you misquoted was about adding
personnel to a LATE project making it later -- nothing to do with how
desirable it can be to add personnel to a large and growing collection
of projects, scaling and growing in an agile, iterative way to meet
equally growing needs and market opportunities).

This specific debate grew from your misuse of "scalable" to mean or
imply "a bazillion feechurz can [[and, implicitly, should]] be added to
a language, and therefore anything that stands in the way of feechuritis
is somehow holding the language back". That's bad enough, even though
in its contextual misuse of "scalable" it breaks new ground, and I don't
want to waste even more time re-treading *old* ground as to whether the
"*insane* extensibility" afforded by macros is a good or a bad thing in
a language to be used for real-world software production (as opposed to
prototyping and research).

No argument. The little Python I wrote while porting Cells to Python was
strikingly attractive. But it was a deal with the devil, unless Python
is content to be just a scripting language. (And it should be.)

It's hard to attribute feelings to a programming language, but, if you
really must, I'd say Pyton aspires to be *useful* -- if all you need is
"just a scripting language", it will be content to be one for you, and
if your need SCALE, well then, PYTHON IS SCALABLE, and will remain a
*SIMPLE, CLEAN, LITTLE AND POWERFUL LANGUAGE* (letting nobody do
anything INSANE to it;-) while scaling up to whatever size of project(s)
you need (including systems so large that they redefine the very concept
of "large scale" -- believe me, once in a while at a conference I make
the mistake of going to some talk about "large scale" this or that, and
invariably stagger out once again with the realization that what's
"large scale" to the world tends to be a neat toy-sized throwaway little
experiment to my current employer).

OK, I propose a duel. We'll co-mentor this:

http://www.lispnyc.org/wiki.clp?page=PyCells

In the end Python will have a Silver Bullet, and only the syntax will
differ, because Python has a weak lambda, statements do not always
return values, it does not have macros, and I do not know if it has
special variables.

Then we can just eyeball the code and see if the difference is
interesting. These abstract discussions do tend to loop.

As a SummerOfCode mentor, I'm spoken for, and can't undertake to mentor
other projects. I do agree that these discussions can be sterile, and
I'll be glad to see what comes of your "pycells" project, but until then
there's little we can do except agree to disagree (save that I'd like
you to acknowledge my point above, regarding what exactly I had said and
the fact that your alleged counterexample doesn't address at all what I
had said -- but, I'll live even without such an acknowledgment).


Alex
 
A

Alex Martelli

Bill Atkins said:
Well, the same technique can obviously be used for:

(let ((|(| 3)))
(+ |(| 4)))
;; => 7

The length of the identifier is irrelevant...

But it cannot be a SINGLE CHARACTER, *just* the openparenthesis.

Wow, it's incredible to me that you STILL can't read, parse and
understand what I have so clearly expressed and repeated!

Common Lisp does not support unnamed macros (how would these be
useful?), but nothing stops me from adding these. What use case do
you envision for anonymous macros?

None, just like there is none for anonymous functions -- there is
nothing useful I can do with anonymous functions that I cannot do with
named ones.

It *is* an important issue, but it's also a subjective issue. I find
Lisp to be far prettier than any syntax-based language, so it's far
from an objective truth that Python code often looks good - or even at
all.

The undeniable truth, the objective fact, is that *to most programmers*
(including ones deeply enamored of Lisp, such as Graham, Tilton, Norvig,
....) Python code looks good; the Lisp code that looks good to YOU (and,
no doubt them), and palatable to me (I have spoken of "eerie beauty"),
just doesn't to most prospective readers. If you program on your own,
or just with a few people who share your tastes, then only your taste
matters; if you want to operate in the real world, maybe, as I've
already pointed out, to build up a successful firm faster than had ever
previously happened, this *DOESN'T SCALE*. Essentially the same issue
I'm explaining on the parallel subthread with Tilton, except that he
fully agrees with my aesthetic sense (quoting Tilton, "No argument. The
little Python I wrote while porting Cells to Python was strikingly
attractive") so this facet of the jewel needed no further belaboring
there.
Plus, I can easily write code that looks good without using a language
that enforces indentation rules. Lisp's regular syntax lets Emacs do
it for me with a simple C-M-a C-M-q. What could be easier?

If you need to edit and reformat other people's code with Emacs to find
it "looks good", you've made my point: code exists to be read, far more
than it's written, and Python's design choice to keep punctuation scarce
and unobtrusive obviates the need to edit and reformat code that way.


Alex
 
B

Bill Atkins

Ken Tilton said:
True but circular, because my very point is that () was a great design
choice in that it made macros possible and they made CL almost
infinitely extensible, while indentation-sensitivity was a mistaken
design choice because it makes for very clean code (I agree
wholeheartedly) but placed a ceiling on its expressiveness.

Having to give functions a name places no "ceiling on expressiveness",
any more than, say, having to give _macros_ a name.

As for:


(defun |(| (aside) (format nil "Parenthetically speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parenthetically speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?

Interestingly, the SECOND lisper to prove himself unable to read the
very text he's quoting. Reread carefully, *USE THE ***SINGLE***
CHARACTER* ... *AS AN ORDINARY IDENTIFIER*. What makes you read a
``PART OF'' that I had never written? You've shown how to use the
characters as *PART* of an identifier [[and I believe it couldn't be the
very start]], and you appear to believe that this somehow refutes my
assertion?

Now I see what the problem is here - you just don't know what you're
talking about. The identifier in Ken's and my samples *is* a single
character identifier. The vertical bars tell the Lisp reader that
what's between them is exempt from other reading rules.

(symbol-name '|(| ) => "("

(length (symbol-name '|(| )) => 1
Are you ready to admit you were utterly wrong, and (while it is indeed
true that my Lisp is rusty) there is nothing in this exchange to show
it, as opposed to showing rustiness in your ability to understand
English? Or shall we move from polite although total dissent right on
to flamewars and namecalling?

Believe it or not, _you_ got it wrong.
The point is, OF COURSE any design choice places limitations on future
design choices; but some limitations are even DESIRABLE (a language
where *every* single isolated character could mean anything whatsoever
would not be "expressive", but rather totally unreadable) or at least
utterly trivial (syntax-sugar level issues most typically are). Wilfully
distorting some such limitation as meaning that one language "can scale"
(when EVERY language inevitably has SOME such limitations) is not even
funny, and clearly characterizes a polemist who is intent on proving a
preconceived thesis, as opposed to an investigator with any real
interest in ascertaining the truth of the matter.

Having to name a variable "paren" instead of "(" is not a serious
restriction. I can't think of a single situation where being able to
do so would be useful.

That said, raw, out-of-the-box Common Lisp can accomodate you if you
both a) need variables named "(" and b) are unwilling to use the bar
syntax. Simply redefine the parenthesis characters in the readtable
(a matter of four function calls) and get this abomination:

{let {{( 3}}
{+ ( 5}}

Lisp places no restrictions on you, even when your goal is as silly as
this one.
Yes, we are, because the debate about why it's better for Python (as a
language used in real-world production systems, *SCALABLE* to extremely
large-scale ones) to *NOT* be insanely extensible and mutable is a
separate one -- Python's uniformity of style allows SCALABILITY of
teams, and teams-of-teams, which is as crucial in the real world as
obviously not understood by you (the law you misquoted was about adding
personnel to a LATE project making it later -- nothing to do with how
desirable it can be to add personnel to a large and growing collection
of projects, scaling and growing in an agile, iterative way to meet
equally growing needs and market opportunities).

Buh? The project doesn't have to be late for Brooks's law to hold;
adding programmers, so goes Brooks reasoning, will always increase the
time required to complete the project because of various communication
issues.
This specific debate grew from your misuse of "scalable" to mean or
imply "a bazillion feechurz can [[and, implicitly, should]] be added to
a language, and therefore anything that stands in the way of feechuritis
is somehow holding the language back". That's bad enough, even though
in its contextual misuse of "scalable" it breaks new ground, and I don't
want to waste even more time re-treading *old* ground as to whether the
"*insane* extensibility" afforded by macros is a good or a bad thing in
a language to be used for real-world software production (as opposed to
prototyping and research).

No argument. The little Python I wrote while porting Cells to Python was
strikingly attractive. But it was a deal with the devil, unless Python
is content to be just a scripting language. (And it should be.)

It's hard to attribute feelings to a programming language, but, if you
really must, I'd say Pyton aspires to be *useful* -- if all you need is
"just a scripting language", it will be content to be one for you, and
if your need SCALE, well then, PYTHON IS SCALABLE, and will remain a
*SIMPLE, CLEAN, LITTLE AND POWERFUL LANGUAGE* (letting nobody do
anything INSANE to it;-) while scaling up to whatever size of project(s)
you need (including systems so large that they redefine the very concept
of "large scale" -- believe me, once in a while at a conference I make
the mistake of going to some talk about "large scale" this or that, and
invariably stagger out once again with the realization that what's
"large scale" to the world tends to be a neat toy-sized throwaway little
experiment to my current employer).

You haven't given much justification for the claim that Python is a
particularly "scalable" language. Sure, Google uses it, Graham gave
it some props somewhere in the middle of his notoriously pro-Lisp
writings, and even Norvig has said good things about it.

Fair enough. But what does Python offer above any garbage-collected
language that makes it so scalable?
 
P

Paul Rubin

(|(| "your Lisp /is/ rusty.")

Interestingly, the SECOND lisper to prove himself unable to read the
very text he's quoting. Reread carefully, *USE THE ***SINGLE***
CHARACTER* ... *AS AN ORDINARY IDENTIFIER*. What makes you read a
``PART OF'' that I had never written? You've shown how to use the
characters as *PART* of an identifier [[and I believe it couldn't be the
very start]], and you appear to believe that this somehow refutes my
assertion?

The identifier there is a single paren. The vertical bars are used to
escape the paren, so that the reader doesn't get confused. The Pythonic
equivalent would be something like

\( = 5

where the backslash escapes the paren. In real Python you could say:

locals()['('] = 5

In Lisp you could get rid of the need to escape the paren if you
wanted, using suitable read macros. Whether that's a good idea is of
course a different matter.
Yes, we are, because the debate about why it's better for Python (as a
language used in real-world production systems, *SCALABLE* to extremely
large-scale ones) to *NOT* be insanely extensible and mutable is a
separate one -- Python's uniformity of style allows SCALABILITY of
teams, and teams-of-teams, which is as crucial in the real world ...

My current take on Lisp vs Python is pretty close to Peter Norvig's
(http://www.norvig.com/python-lisp.html):

Python has the philosophy of making sensible compromises that make
the easy things very easy, and don't preclude too many hard
things. In my opinion it does a very good job. The easy things are
easy, the harder things are progressively harder, and you tend not
to notice the inconsistencies. Lisp has the philosophy of making
fewer compromises: of providing a very powerful and totally
consistent core. This can make Lisp harder to learn because you
operate at a higher level of abstraction right from the start and
because you need to understand what you're doing, rather than just
relying on what feels or looks nice. But it also means that in
Lisp it is easier to add levels of abstraction and complexity;
Lisp makes the very hard things not too hard.
It's hard to attribute feelings to a programming language, but, if you
really must, I'd say Pyton aspires to be *useful* -- if all you need is
"just a scripting language", it will be content to be one for you, and
if your need SCALE, well then, PYTHON IS SCALABLE, and will remain a
*SIMPLE, CLEAN, LITTLE AND POWERFUL LANGUAGE* (letting nobody do
anything INSANE to it;-) while scaling up to whatever size of project(s)
you need (including systems so large that they redefine the very concept
of "large scale" -- believe me, once in a while at a conference I make
the mistake of going to some talk about "large scale" this or that, and
invariably stagger out once again with the realization that what's
"large scale" to the world tends to be a neat toy-sized throwaway little
experiment to my current employer).

I've heard many times that your current employer uses Python for all
kinds of internal tools; I hadn't heard that it was used in Very Large
projects over there. I'd be interested to hear how that's been
working out, since the biggest Python projects I'd heard of before
(e.g. Zope) are, as you say, toy-sized throwaways compared to the
stuff done regularly over there at G.
 
P

Paul Rubin

Bill Atkins said:
Fair enough. But what does Python offer above any garbage-collected
language that makes it so scalable?

I think what used to be Lisp culture now uses the *ML languages or
Haskell. It's only throwbacks (which includes me sometimes) who still
use Lisp. I've been wanting for a while to do something in ML but
just haven't worked up enough steam for it. Python really does make
small and medium-sized tasks easy, even compared with Lisp. I'm still
reserving judgement about how it is at large tasks.
 
K

Ken Tilton

Alex said:
True but circular, because my very point is that () was a great design
choice in that it made macros possible and they made CL almost
infinitely extensible, while indentation-sensitivity was a mistaken
design choice because it makes for very clean code (I agree
wholeheartedly) but placed a ceiling on its expressiveness.


Having to give functions a name places no "ceiling on expressiveness",
any more than, say, having to give _macros_ a name.


As for:



(defun |(| (aside) (format nil "Parenthetically speaking...~a." aside))
=> |(|
(|(| "your Lisp /is/ rusty.")
=> "Parenthetically speaking...your Lisp /is/ rusty.."

:) No, seriously, is that all you can come up with?


Interestingly, the SECOND lisper to prove himself unable to read the
very text he's quoting. Reread carefully, *USE THE ***SINGLE***
CHARACTER* ... *AS AN ORDINARY IDENTIFIER*. What makes you read a
``PART OF'' that I had never written? You've shown how to use the
characters as *PART* of an identifier [[and I believe it couldn't be the
very start]], and you appear to believe that this somehow refutes my
assertion?

The function name here:

(|(| "Boy, your Lisp is rusty")
-> Boy, your Lisp is rusty.

....is exactly one (1) character long.

(length (symbol-name'|(|) -> 1

Why? (symbol-name '|(|) -> "(" (No, the "s are not part of the name!)

If you want to argue about that, I will have to bring up the Lisp
readtable. Or did you forget that, too?

:)

kenny

--
Cells: http://common-lisp.net/project/cells/

"Have you ever been in a relationship?"
Attorney for Mary Winkler, confessed killer of her
minister husband, when asked if the couple had
marital problems.
 
B

Bill Atkins

But it cannot be a SINGLE CHARACTER, *just* the openparenthesis.

Wow, it's incredible to me that you STILL can't read, parse and
understand what I have so clearly expressed and repeated!

Read my other post. It's incredible that you STILL haven't considered
the possibility that you're just wrong.
None, just like there is none for anonymous functions -- there is
nothing useful I can do with anonymous functions that I cannot do with
named ones.

Sure there are.

Does Python have any support for closures? If so, ignore this point.
But if not, what about examples like this:

(defun make-window (window observer)
;; initialization code here
(add-handler window 'close
(lambda (event)
(notify observer event)))
;; more code)

Being able to keep pass around state with functions is useful.

There are also cases where a function is so trivial that the simplest
way to describe it is with its source code, where giving it a name and
putting it at the beginning of a function is just distracting and
time-consuming. E.g.:

(remove-if (lambda (name)
(find #\- name :test #'char=))
list-of-names)

What's the sense of giving that function its own name? It's much
clearer to simply write it in place. Yes, it's _possible_ to use
named functions, but in this case its functionality is so simple that
it's clearer to simply type it in place. Why is this expressiveness a
bad thing, aside from its power to wreck an indentation-significant
language?
The undeniable truth, the objective fact, is that *to most programmers*
(including ones deeply enamored of Lisp, such as Graham, Tilton, Norvig,
...) Python code looks good; the Lisp code that looks good to YOU (and,
no doubt them), and palatable to me (I have spoken of "eerie beauty"),
just doesn't to most prospective readers. If you program on your own,
or just with a few people who share your tastes, then only your taste
matters; if you want to operate in the real world, maybe, as I've
already pointed out, to build up a successful firm faster than had ever
previously happened, this *DOESN'T SCALE*. Essentially the same issue
I'm explaining on the parallel subthread with Tilton, except that he
fully agrees with my aesthetic sense (quoting Tilton, "No argument. The
little Python I wrote while porting Cells to Python was strikingly
attractive") so this facet of the jewel needed no further belaboring
there.

And I'm sure Kelly Clarkson sounds better *to most listeners* but that
doesn't mean she's a better musician than Hendrix. The fact that most
people are used to ALGOL-like languages does not mean that ALGOL-like
languages are more aesthetically pleasing on their own merits.
If you need to edit and reformat other people's code with Emacs to find
it "looks good", you've made my point: code exists to be read, far more
than it's written, and Python's design choice to keep punctuation scarce
and unobtrusive obviates the need to edit and reformat code that way.

That's not what I'm saying at all. My point is that I can write a
function, counting on Emacs to keep it indented for me, and then after
making a series of changes to it, a mere C-M-a C-M-q takes them into
account and bam, no-fuss indenting.
 
P

Paul Rubin

Bill Atkins said:
Does Python have any support for closures? If so, ignore this point.
But if not, what about examples like this:

(defun make-window (window observer)
;; initialization code here
(add-handler window 'close
(lambda (event)
(notify observer event)))
;; more code)

Python has closures but you can only read the closed variables, not
write them.
Being able to keep pass around state with functions is useful.

There are also cases where a function is so trivial that the simplest
way to describe it is with its source code, where giving it a name and
putting it at the beginning of a function is just distracting and
time-consuming. E.g.:

(remove-if (lambda (name)
(find #\- name :test #'char=))
list-of-names)

If I read that correctly, in Python you could use

filter(list_of_names, lambda name: '-' not in name)
or
[name for name in list_of_names if '-' not in name]

Both of these have become more natural for me than the Lisp version.
 
C

Cameron MacKinnon

Alex said:
Having to give functions a name places no "ceiling on expressiveness",
any more than, say, having to give _macros_ a name.

As was pointed out, if a Lisper wants anonymous macros, it's a cinch to
create a scheme to allow this. Whether or not it's a good idea in
general, if someone feels they need it, they can do it. An attitude like
that beats "No you can't do that, but you shouldn't do it anyway."
Interestingly, the SECOND lisper to prove himself unable to read the
very text he's quoting. Reread carefully, *USE THE ***SINGLE***
CHARACTER* ... *AS AN ORDINARY IDENTIFIER*. What makes you read a
``PART OF'' that I had never written? You've shown how to use the
characters as *PART* of an identifier [[and I believe it couldn't be the
very start]], and you appear to believe that this somehow refutes my
assertion?

Those vertical bars are just quoting characters, rather like the quoting
characters you'd undoubtedly need in Python to create a variable name
with a space in it.
The point is, OF COURSE any design choice places limitations on future
design choices; but some limitations are even DESIRABLE (a language
where *every* single isolated character could mean anything whatsoever
would not be "expressive", but rather totally unreadable) or at least
utterly trivial (syntax-sugar level issues most typically are).

Yeah, a language like that would probably have some strange name like
"TeX." But we'd never know, because nobody would ever use it.

Yes, we are, because the debate about why it's better for Python (as a
language used in real-world production systems, *SCALABLE* to extremely
large-scale ones) to *NOT* be insanely extensible and mutable is a
separate one -- Python's uniformity of style allows SCALABILITY of
teams, and teams-of-teams, which is as crucial in the real world as
obviously not understood by you (the law you misquoted was about adding
personnel to a LATE project making it later -- nothing to do with how
desirable it can be to add personnel to a large and growing collection
of projects, scaling and growing in an agile, iterative way to meet
equally growing needs and market opportunities).

You seem to be using the most primitive definition of scalable that
there is, viz, if one coder can write one one page program in a day, two
coders can write two (or more likely 1.8) one page programs in a day.
Lispers tend to the view that *OF COURSE* most other decent languages
scale linearly, but what we want is force multipliers and exponential
scaling, not "throw money at it" scaling. Thus program writing programs,
program analyzing programs, compiled domain specific languages and great
quotes like

"I'd rather write programs to write programs than write programs."

"Programs that write programs are the happiest programs in the world."
 
I

I V

There are also cases where a function is so trivial that the simplest
way to describe it is with its source code, where giving it a name and
putting it at the beginning of a function is just distracting and
time-consuming. E.g.:

(remove-if (lambda (name)
(find #\- name :test #'char=))
list-of-names)

What's the sense of giving that function its own name? It's much
clearer to simply write it in place. Yes, it's _possible_ to use
named functions, but in this case its functionality is so simple that
it's clearer to simply type it in place. Why is this expressiveness a
bad thing, aside from its power to wreck an indentation-significant
language?

Well, you can do that with python's current,
non-indentation-significance-wrecking, lambda syntax, so I don't think
that's a particularly persuasive example. Note also that the only
limitation python has on where you can define functions is that you can't
define them inside expressions (they have to be statements), so you could
define a named function right before the call to remove-if, which removes
some of the advantage you get from the lambda (that is, the function
definition is not very far from when it's used).

Actually, I think the limitation on python that is operative here is not
significant whitespace, but the distinction between statements and
expressions.

(crossposts trimmed)
 
B

Bill Atkins

Yes, we are, because the debate about why it's better for Python (as a
language used in real-world production systems, *SCALABLE* to extremely
large-scale ones) to *NOT* be insanely extensible and mutable is a
separate one -- Python's uniformity of style allows SCALABILITY of
teams, and teams-of-teams, which is as crucial in the real world as
obviously not understood by you (the law you misquoted was about adding
personnel to a LATE project making it later -- nothing to do with how
desirable it can be to add personnel to a large and growing collection
of projects, scaling and growing in an agile, iterative way to meet
equally growing needs and market opportunities).

This specific debate grew from your misuse of "scalable" to mean or
imply "a bazillion feechurz can [[and, implicitly, should]] be added to
a language, and therefore anything that stands in the way of feechuritis
is somehow holding the language back". That's bad enough, even though
in its contextual misuse of "scalable" it breaks new ground, and I don't
want to waste even more time re-treading *old* ground as to whether the
"*insane* extensibility" afforded by macros is a good or a bad thing in
a language to be used for real-world software production (as opposed to
prototyping and research).

It's interesting how much people who don't have macros like to put
them down and treat them as some arcane art that are too "*insane*"ly
powerful to be used well.

They're actually very straightforward and can often (shock of shocks!)
make your code more readable, without your efficiency taking a hit.

For example, at work I recently had to generate PDF reports in PHP.
Certain sections would need to be indented, and then once they were
done, I wanted to move back out to the previous level of indentation.
I ended up with stuff like this (totally made up on the spot, but
conveys the general idea):

function out_main_text( ) {
$old_indent = $pdf->indentation;
$pdf->indent_to( $pdf->indentation + 4 );

out_header();
out_facts();

$pdf->set_indentation( $old_indent );
}

function out_header() {
$old_indent = $pdf->indentation;
$pdf->indent_to( $pdf->indentation + 4 );

$pdf->write( "some text" );

$pdf->set_indentation( $old_indent );
}

function out_facts() {
$old_indent = $pdf->indentation;
$pdf->indent_to( $pdf->indentation + 4 );

out_some_subsection();
out_another_subsection();

$pdf->set_indentation( $old_indent );
}


Obviously, this is very much pseudocode. The point is that managing
indentation was a hassle, because each of these subfunctions indents
to a new position. This can pretty clearly get tedious, and is
definitely error-prone, especially when you consider that different
groups of functions are called depending upon the input and that some
of the functions might return early.

But why should I have to worry about any of this? Why can't I do:

(with-indentation (pdf (+ (indentation pdf) 4))
(out-header)
(out-facts))

and then within, say out-facts:

(with-indentation (pdf (+ (indentation pdf) 4))
(write pdf "some text"))

More readable, and no bookkeeping to worry about. This is great! And
here's the macro:

(defmacro with-indentation (pdf new-value &body body)
(let ((old-indent (gensym)))
`(let ((,old-indent (indentation pdf)))
(unwind-protect (progn ,@body)
(setf (indentation pdf) ,old-indent)))))

Bam, all of that bookkeeping, all of those potential errors have taken
care of themselves. WITH-INDENTATION will expand into code that uses
UNWIND-PROTECT to ensure that the indentation always gets returned to
its previous value, even if an exception occurs or the code within
calls RETURN. The WITH-INDENTATION call sets up an environment where
there is a new indentation level in effect, and then cleans it up when
it's done. I can nest these to my heart's content.

Obviously, to someone totally unfamiliar with Lisp, the contents of
that macro are pretty daunting. But you're crazy if you argue that
having WITH-INDENTATION around isn't an improvement over manually
ensuring that indentation gets saved and restored for every function
call.

I could even generalize this (as CLISP does) to this:

(letf (((indentation pdf) (+ 4 (indentation pdf))))
(write "some text"))

Now I can use LETF to temporarily set any value at all for as long as
the code inside is running, and to restore it when it's done.

Macros rock.
 
B

Bill Atkins

I V said:
Well, you can do that with python's current,
non-indentation-significance-wrecking, lambda syntax, so I don't think
that's a particularly persuasive example. Note also that the only
limitation python has on where you can define functions is that you can't
define them inside expressions (they have to be statements), so you could
define a named function right before the call to remove-if, which removes
some of the advantage you get from the lambda (that is, the function
definition is not very far from when it's used).

Actually, I think the limitation on python that is operative here is not
significant whitespace, but the distinction between statements and
expressions.

(crossposts trimmed)

You're right, I was replying to Alex's assertion that "there is
nothing useful I can do with anonymous functions that I cannot do with
named ones."
 
A

Alex Martelli

Bill Atkins said:
Does Python have any support for closures? If so, ignore this point.

Ignored, since closures are there.
Being able to keep pass around state with functions is useful.

Sure, but naming the functions doesn't hamper that.
There are also cases where a function is so trivial that the simplest
way to describe it is with its source code, where giving it a name and
putting it at the beginning of a function is just distracting and
time-consuming. E.g.:

(remove-if (lambda (name)
(find #\- name :test #'char=))
list-of-names)

What's the sense of giving that function its own name? It's much
clearer to simply write it in place. Yes, it's _possible_ to use
named functions, but in this case its functionality is so simple that
it's clearer to simply type it in place. Why is this expressiveness a
bad thing, aside from its power to wreck an indentation-significant
language?

Offering several "equivalently obvious" approaches to performing just
one same task is bad for many reasons: you end up with a bigger language
(with all the attending ills) with no extra power, and you diminish the
style uniformity of programs written in the language, hampering the
ability of many people to work in the same codebase with no "ownership".

Like most all design principles, "there should be one, and preferably
only one, obvious way to perform a task" is an _ideal_, unattainable in
its perfect form in this sublunar world; but I find it an extremely
helpful guideline to design, and it does pervade Python (many of the
planned improvements for the future Python 3.0, which will be allowed to
be backwards-incompatible with 2.*, involve *removing* old features
made, in this sense, redundant by enhancements in recent versions; my
only beef here is that _not enough_ is scheduled for removal, alas).

people are used to ALGOL-like languages does not mean that ALGOL-like
languages are more aesthetically pleasing on their own merits.

"on their own merits" can't be the case -- as Wittgenstein pointed out,
we ARE talking about the natural history of human beings. A frequently
observed aestethic preference for X over Y says nothing about X and Y
``on their own merits'' (if such noumena could even be envisaged), but
it's empirically important about X and Y _when many human beings must
interact with them_.

Being "used to" some kinds of languages has nothing to do with it: when
I met Python I was most "used to" perl (and cognizant of Forth, scheme,
pre-common Lisp, sh, APL, ...), nevertheless Python immediately struck
me as allowing particularly beautiful coding. And I specifically named
many Lisp experts as acknowledging exacty the same thing, further
demolishing your "used to" strawman...


Alex
 
A

Alex Martelli

Bill Atkins said:
Believe it or not, _you_ got it wrong.

Acknowledged: Common Lisp is even MORE insane (note that the quote
"INSANELY extensible" is from Tilton) than I believed -- I'm pretty sure
that the Lisp dialects I used in 1979-1981 didn't go to such crazy
extremes, and neither did Scheme.
Buh? The project doesn't have to be late for Brooks's law to hold;
adding programmers, so goes Brooks reasoning, will always increase the
time required to complete the project because of various communication
issues.

And here is where we check if you're as gracious about admitting your
errors, as I am about mine. Brooks' law is:

"""Adding manpower to a late software project makes it later."""

These are Brooks' words, literally. OK so far?

Your claim, that adding programmers will ALWAYS increase the time, is
not just wrong, but utterly ridiculous. I can't put it better than the
wikipedia:
"""
Misconceptions

A commonly understood implication of Brooks' law is that it will be more
productive to employ a smaller number of very talented (and highly paid)
programmers on a project than to employ a larger number of less talented
programmers, since individual programmer productivity can vary greatly
between highly talented and efficient programmers and less talented
programmers. However, Brooks' law does not mean that starving a project
of resources by employing fewer programmers beyond a certain point will
get it done faster.
"""

Moreover, check out the research on Pair Programming: it scientifically,
empirically confirms that "two heads are better than one", which should
surprise nobody. Does this mean that there aren't "various
communication issues"? Of course there are, but there's no implied
weighting of these factors wrt the _advantages_ of having that second
person on the team (check the Pair Programming literature for long lists
of those advantages).

Only empirical research can tell us where the boundary is -- when
productivity is decreased by going from N to N+1. A lot depends on
imponderable issues such as personality meshes or clashes, leadership
abilities at hands, methodology used, etc. All of this is pretty
obvious, making your assertion that Brooks held otherwise actionable (as
libel, by Brooks) in many legislations.

As it happens, I also have examples in which adding (a few carefully
selected) people to a software project that WAS (slightly) late put that
project back on track and made it deliver successfully on schedule.
Definitely not the "pointy-haired boss" management style of "throwing
warm bodies at the problem" that Brooks was fighting against, but,
consider: the project's velocity has suffered because [a] the tech lead
has his personal (usually phenomenal) productivity hampered by a painful
condition requiring elective surgery to abate, and nobody on the
team is really super-experienced in the intricacies of cryptography, yes
some very subtle cryptographic work turns out to be necessary. One day,
the tech lead calls in -- the pain has gotten just too bad, he's going
for surgery, and will be out of the fray for at least one week.

I still remember with admiration how my Director reacted to the
emergency: he suspended two other projects, deciding that, if THEIR
deadlines were broken, that would be a lesser damage to the company than
if this one slipped any further; and cherrypicked exactly two people --
one incredibly flexible "jack of all trades" was tasked with getting up
to speed on the project and becoming the acting TL for it, and an
excellent cryptography specialist was tasked to dig deep into the
project's cryptography needs and solve them pronto.

So, We Broke Brooks' Law -- the cryptographer did his magic, and
meanwhile the JOAT ramped up instantly and took the lead (kudos to the
Jack's skills, to the clarity and transparency of the previous TL's
work, to the agile methodologies employed throughout, AND to the
uniformity of style of one language which will stay unnamed here)... and
the project delivered on time and within budget. We had one extra
person (two "replacements" for one TL's absence), yet it didn't make the
late software project even later -- it brought it back on track
perfectly well.

I have many other experiences where _I_ was that JOAT (and slightly
fewer ones where I was the specialist -- broadly speaking, I'm more of a
generalist, but, as needs drive, sometimes I do of necessity become the
specialist in some obscure yet necessary technology... must have
happened a dozen times over the 30 years of my careers, counting
graduate school...).

This set of experiences in no way tarnishes the value of Brooks' Law,
but it does *put it into perspective*: done JUST RIGHT, by sufficiently
brilliant management, adding A FEW people with exactly the right mix of
skills and personality to a late software project CAN save the bacon,

Fair enough. But what does Python offer above any garbage-collected
language that makes it so scalable?

Uniformity of style, facilitating egoless programming; a strong cultural
bias for simplicity and clarity, and against cleverness and obscurity;
"just the right constraints" (well, mostly;-), such as immutability at
more or less the right spots (FP languages, with _everything_ immutable,
have an edge there IN THEORY... but in practice, using them most
effectively requires a rare mindset/skillset, making it hard to "scale
up" teams due to the extra difficulty of finding the right people).


Alex
 
A

Alex Martelli

Paul Rubin said:
My current take on Lisp vs Python is pretty close to Peter Norvig's
(http://www.norvig.com/python-lisp.html):

Python has the philosophy of making sensible compromises that make
the easy things very easy, and don't preclude too many hard
things. In my opinion it does a very good job. The easy things are
easy, the harder things are progressively harder, and you tend not
to notice the inconsistencies. Lisp has the philosophy of making
fewer compromises: of providing a very powerful and totally
consistent core. This can make Lisp harder to learn because you
operate at a higher level of abstraction right from the start and
because you need to understand what you're doing, rather than just
relying on what feels or looks nice. But it also means that in
Lisp it is easier to add levels of abstraction and complexity;
Lisp makes the very hard things not too hard.

Sure -- however, Python makes them not all that hard either. Peter and
I have uncannily similar tastes -- just last month we happened to meet
at the same Arizona Pueblo-ancestral-people ruins-cum-museum (we both
independently chose to take vacation during spring break week to take
the kids along, we both love the Grand Canyon region, we both love
dwelling on ancient cultures, etc -- so I guess the coincidence wasn't
TOO crazy -- but it still WAS a shock to see Peter walk into the museum
at the same time I was walking out of it!-). Yes, it IS easier to add
complexity in Lisp; that's a good summary of why I prefer Python.

I've heard many times that your current employer uses Python for all
kinds of internal tools; I hadn't heard that it was used in Very Large
projects over there. I'd be interested to hear how that's been
working out, since the biggest Python projects I'd heard of before
(e.g. Zope) are, as you say, toy-sized throwaways compared to the
stuff done regularly over there at G.

Sorry, but I'm not authorized to speak for my employer nor to reveal
details of our internal systems -- hey, I cannot even say how many
servers we have; the "corporate approved metrics" is ``several
thousands''...;-). The most that managed to get approved for external
communication you'll find in the "Python at Google" presentation that
Chris di Bona and Greg Stein hold at times in various venues, and that's
not saying much -- good thing I'm not the one giving those
presentations, as I might find hard to stick to the approved line;-)


Alex
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,062
Latest member
OrderKetozenseACV

Latest Threads

Top