A critic of Guido's blog on Python's lambda
6 answers - 4903 bytes -

Steve R. Hastings wrote:
Fri, 05 May 2006 21:16:50 -0400, Ken Tilton wrote:
The upshot of
what he wrote is that it would be really hard to make semantically
meaningful indentation work with lambda.
Pretty much correct. The complete thought was that it would be painful
all out of proportion to the benefit.
See, you don't need multi-line lambda, because you can do this:
--
def make_adder(x):
def adder_func(y):
sum = x + y
return sum
return adder_func
Now imagine you had to do this with every object.
def add_five(x)
# return x + 5 <-- anonymous integer literal, not allowed!!!
five = 5 # define it first
return x + five
Think about the ramifications of every object having to have a name in
some environment, so that at the leaves of all expressions, only names
appear, and literals can only be used in definitions of names.
Also, what happens in the caller who invokes make_adder? Something like
this:
adder = make_adder(42)
perhaps even something like this
make_adder(2)(3) 5
Look, here the function has no name. Why is that allowed? If anonymous
functions are undesireable, shouldn't there be a requirement that the
result of make_adder has to be bound to a name, and then the name must
be used?
Note that make_adder() doesn't use lambda, and yet it makes a custom
function with more than one line. Indented, even.
That function is not exactly custom. What is custom are the environment
bindings that it captures. The code body comes from the program itself.
What about actually creating the source code of a function at run-time
and compiling it?
(let ((source-code (list 'lambda (list 'x 'y) )))
(compile nil source-code))
Here, we are applying the compiler (available at run-time) to syntax
which represents a function. The compiler analyzes the syntax and
compiles the function for us, giving us an object that can be called.
Without that syntax which can represent a function, what do you pass to
the compiler?
If we didn't have lambda in Lisp, we could still take advantage of the
fact that the compiler can also take an interpreted function object and
compile that, rather than source code. So we could put together an
expression which looks like this:
(flet ((some-name (x y) )) #'some-name)
We could EVAL this expression, which would give us a function object,
which can then be passed to CMPILE. So we have to involve the
evaluator in addition to the compiler, and it only works because the
compiler is flexible enough to accept function objects in addition to
source code.
No; lambda is a bit more convenient. But this doesn't seem like a very
big issue worth a flame war. If GvR says multi-line lambda would make
the lexer more complicated and he doesn't think it's worth all the effort,
I don't see any need to argue about it.
I.e. GvR is the supreme authority. If GvR rationalizes something as
being good for himself, that's good enough for me and everyone else.
I won't say more, since Alex Martelli already pointed out that Google is
doing big things with Python and it seems to scale well for them.
That's pretty amazing for something that doesn't even have a native
compiler, and big mutexes in its intepreter core.
Look at "docs.python.org" in section 8.1 en titled "Thread State and
the Global Interpreter Lock":
"The Python interpreter is not fully thread safe. In order to support
multi-threaded Python programs, there's a global lock that must be held
by the current thread before it can safely access Python objects.
Without the lock, even the simplest operations could cause problems in
a multi-threaded program: for example, when two threads simultaneously
increment the reference count of the same object, the reference count
could end up being incremented only once instead of twice. Therefore,
the rule exists that only the thread that has acquired the global
interpreter lock may operate on Python objects or call Python/C API
functions. In order to support multi-threaded Python programs, the
interpreter regularly releases and reacquires the lock -- by default,
every 100 bytecode instructions (this can be changed with
sys.setcheckinterval())."
That doesn't mean you can't develop scalable solutions to all kinds of
problems using Python. But it does mean that the scalability of the
overall solution comes from architectural details that are not related
to Python itself. Like, say, having lots of machines linked by a fast
network, working on problems that decompose along those lines quite
nicely.
No.1 | | 1734 bytes |
| 
Kaz Kylheku wrote:
Now imagine you had to do this with every object.
def add_five(x)
# return x + 5 <-- anonymous integer literal, not allowed!!!
five = 5 # define it first
return x + five
I mentioned that as Slippery slope fallacious argument in other reply.
[]
That doesn't mean you can't develop scalable solutions to all kinds of
problems using Python. But it does mean that the scalability of the
overall solution comes from architectural details that are not related
to Python itself. Like, say, having lots of machines linked by a fast
network, working on problems that decompose along those lines quite
nicely.
Is there such language that allow scalability without any need for
design on the underlying architecture?
Python doesn't obscure or become obstacle in utilise those
architecture. Python allow one to design scalable architecture. So
Python IS scalable, isn't it? when Python prevent the up-scaling
or Python made scaled up project unmanagable that you can say that
Python is not scalable.
In 'Team scalable' axis, Python is easy to learn for average
programmer. So it is easier for Python to scale up.
'Data scalable' axis is language neutral, it depends on how you
architecture your database, etc.
'User requirement scalable' axis require both infrastructure and
language to provide:
No matter how scalable your language is, you cannot make a 100MHz/128MB
server serve 100,000 client a second over the internet.
No matter how many server and load balancing you have, you cannot
practically program gmail using purely MS-DS bat file.
No.2 | | 800 bytes |
| 
Pisin Bootvong <joesb.coe9 (AT) gmail (DOT) comwrote:
+
| No matter how scalable your language is, you cannot make a 100MHz/128MB
| server serve 100,000 client a second over the internet.
+
Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
a 100BASE-TX NIC] is plenty to service 100K *small* requests/s ;-}
course, you might have to write it in assembler on bare metal,
but the good news is that with only a 1000 cycle budget, at least
the code won't be very large! ;-}
-Rob [someone who remembers 0.5 MIPS DEC PDP-10s being used
for >100 simultaneous commercial timesharing users]
Rob Warnock<rpw3 (AT) rpw3 (DOT) org>
627 26th Avenue<URL:http://rpw3.org/>
San Mateo, CA 94403(650)572-2607
No.3 | | 1041 bytes |
| 
Rob Warnock wrote:
Pisin Bootvong <joesb.coe9 (AT) gmail (DOT) comwrote:
+
| No matter how scalable your language is, you cannot make a 100MHz/128MB
| server serve 100,000 client a second over the internet.
+
Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
a 100BASE-TX NIC] is plenty to service 100K *small* requests/s ;-}
course, you might have to write it in assembler on bare metal,
but the good news is that with only a 1000 cycle budget, at least
the code won't be very large! ;-}
Well, I was really asking for a service that really service something
complicate and useful though :-D
And donot forget to account for S CPU time (well may be you can write
your own S for it too :-D )
-Rob [someone who remembers 0.5 MIPS DEC PDP-10s being used
for >100 simultaneous commercial timesharing users]
Rob Warnock<rpw3 (AT) rpw3 (DOT) org>
627 26th Avenue<URL:http://rpw3.org/>
San Mateo, CA 94403(650)572-2607
No.4 | | 1514 bytes |
| 
Pisin Bootvong <joesb.coe9 (AT) gmail (DOT) comwrote:
+
| Rob Warnock wrote:
| | No matter how scalable your language is, you cannot make a
| | 100MHz/128MB server serve 100,000 client a second over the internet.
| +
| >
| Sure you can! That's ~1000 CPU cycles/request, which [assuming at least
| a 100BASE-TX NIC] is plenty to service 100K *small* requests/s ;-}
|
| Well, I was really asking for a service that really service something
| complicate and useful though :-D
+
If "only" being useful is enough, 100 cycles is enough for a DNS server,
or an NTP server, or even a stub HTTP server that delivers some small
piece of real-time data, like a few realtime environmental sensors
[temperature, voltages, etc.].
+
| course, you might have to write it in assembler on bare metal,
| but the good news is that with only a 1000 cycle budget, at least
| the code won't be very large! ;-}
|
| And donot forget to account for S CPU time (well may be you can write
| your own S for it too :-D )
+
Uh What I meant by "bare metal" is *no* "/S" per se, only a
simple poll loop servicing the attention flags[1] of the various
I/ devices -- a common style in lightweight embedded systems.
-Rob
[1] a.k.a. "interrupt request" bits, except with interrupts not enabled.
Rob Warnock<rpw3 (AT) rpw3 (DOT) org>
627 26th Avenue<URL:http://rpw3.org/>
San Mateo, CA 94403(650)572-2607
No.5 | | 572 bytes |
| 
Pisin Bootvong <joesb.coe9 (AT) gmail (DOT) comwrote:
Is there such language that allow scalability without any need for
design on the underlying architecture?
Perhaps Erlang? I have no specific experience with it, but according
to the rumor mill it forces or cajoles you into an architecture that's
quite appropriate for scaling -- i.e., sure that architecture needed to
be designed, but (if I understand Erlang correctly) it's now built into
the language and you're more or less going to use the right paradigm.
Alex
No.6 | | 1187 bytes |
| 
Rob Warnock <rpw3 (AT) rpw3 (DOT) orgwrote:
If "only" being useful is enough, 100 cycles is enough for a DNS server,
or an NTP server, or even a stub HTTP server that delivers some small
piece of real-time data, like a few realtime environmental sensors
[temperature, voltages, etc.].
Reminds me of Stuart Cheshire's description of how they managed to
shoehorn zeroconf (aka bonjour, the artist formerly known as rendezvous)
into a risible amount of RM (less than 1K byte, if I recall correctly)
left in an embedded microcontroller (for a video camera, I think).
Zeroconf is at heart a few clever tricks on top of DNS (plus 169.254.*
IPs), and in the end they managed by one more clever trick (the thingy
ignores WHAT the request is for, and just spits out the same response
each and every time -- pushing the boundaries of DNS but, it seems,
still technically staying within those boundaries;-).
Not directly relevant to the scaling debate (the camera's expected to be
on a LAN, serving a few requests per second at most), but the limit
being on bits rather than cycles somehow "tastes" similar to me.
Alex