Steven D'Aprano said:
Here, you've basically shot yourself in the ass. Appealing to
Turing completeness when talking about programming language
features is about the dumbest thing you can make. In Turing sense,
a program is simply a function that takes an argument and returns a
value. It doesn't say anything about how this function was
implemented. It could be Turing machine, lambda calculus, Markov
chains or whatever else. All these methods produce the same set of
programs, but that doesn't mean you could implement lambda in
Turing machine for example.
[...]
If you're talking about practicality, then of course you're correct,
not all languages are equally expressive. Some languages are not
expressive enough.
I agree.
Some languages are too expressive.
I disagree. "Too expressive"--what a thing to say.
[...]
Look, all snarkiness aside, it just isn't true that "stuff like this
is impossible in other languages". If Wolfram Fenske had said "stuff
like this isn't easy in many other languages" he would have been
right.
I said that it's impossible to write you own object system in other
languages *and* have it behave like it was part of the language. OK,
you could always write your own pre-processor, i. e., your own
Foo+Objects to Foo compiler. But that's almost like saying it's
impossible. Now, object systems aside, how about that one: One of the
new features of Python 2.5 is a syntax for
--8<---------------cut here---------------start------------->8---
if condition:
x = true_value
else:
x = false_value
--8<---------------cut here---------------end--------------->8---
which becomes
--8<---------------cut here---------------start------------->8---
x = true_value if condition else false_value
--8<---------------cut here---------------end--------------->8---
(see [1]). IMO that's a nice addition because this pattern is
something that has bothered me for some time.
Here's another one, the "with" statement [2]:
--8<---------------cut here---------------start------------->8---
Some standard Python objects now support the context management
protocol and can be used with the 'with' statement. File objects are
one example:
with open('/etc/passwd', 'r') as f:
for line in f:
print line
... more processing code ...
After this statement has executed, the file object in f will have been
automatically closed, even if the 'for' loop raised an exception
part-way through the block.
--8<---------------cut here---------------end--------------->8---
My point is that in Python--and AFAIK any other language except maybe
OCaml and maybe maybe Haskell--, you have to wait for these changes
until the language designers decide to make the for you. And if they
don't, you're out of luck. In Lisp, you can just add this yourself.
And if he had said "and stuff like this carries risks as well as
benefits" he would have come across as less of a language fanatic.
Sure, you can shoot yourself in the foot with macros. But you can do
that in any language of any degree of expressiveness [3]. Come to
think of it, the whole reason why we use high level languages is
because of their expressiveness: We get stuff done faster and
introduce less errors. So "the more expressive, the better," right?
But according to you, there's a point when a language gets "too
expressive". I don't see why.
One of the risks with Python is the ease with which you can modify the
built-ins. An expression like list(2, 3, 4) doesn't necessarily create a
list from 2, 3, and 4, because the built-in list could be redefined.
(In practice, that's not often a real problem, because experienced
Python developers simply learn not to needlessly or confusingly shadow
built-ins. It's not the best system, but it works well enough in
practice.)
So you do trust your developers not to do anything stupid.
But at least the basic syntax and keywords of the language are known
to be constant. With Lisp macros, even that isn't guaranteed.
Let me summarize: you're allowed to redefine every built-in function
you want but introducing new syntax is simply too much. See, this is
the kind of thinking I don't understand. I say macros are good
because a), b), and c) and you answer macros are bad because, uhm,
well, it would be pure anarchy.
Now, if Lispers would say "Oh yes, macros give you great power, and
with great power comes great responsibility. Be careful." then, no
doubt, we'd take you guys more seriously.
Sure, it's a powerful tool but it's not *that* hard to use. Maybe
you're afraid of it because that it's something that's unique to Lisp?
But IMO the reason for that is not that they're too powerful. IMO it
has mostly to do with the fact that other languages' syntaxes make it
too difficult to implement Lisp-style macros.
But we don't hear that -- we hear Lispers going on and on about how
great it is that they can easily redefine every corner of the
language. Do you blame people for *believing them* and imagining
that reading Lisp code is like following some ghostly
will-o-the-wisp across a swamp, where nothing is what it seems and
the landscape is forever shifting?
Come on! You're telling me people don't learn Lisp because they are
afraid of it? Python allows you to redefine built-in functions, as
you said, Ruby allows you to attach new methods to live objects, but
Lisp is simply going too far?
Now, if you want to tell me that, despite all the talk, Lisp coders
don't actually create new syntax or mini-languages all that often,
that they just use macros as functions, then the question becomes:
why do you need macros then if you are just using them as functions?
Why not use functions?
Easy because macros are not functions. Functions allow you abstract
functionality, macros allow you abstract syntax. Look at the examples
above. How would you implement conditional expressions as a function?
Answer: You can't, it's syntax.
Footnotes:
[1] <
http://docs.python.org/whatsnew/pep-308.html>
[2] <
http://docs.python.org/whatsnew/pep-343.html>
[3] And here's the proof
<
http://www.reed.edu/~tuckers/jokes/foot.html>
