SIGUSR2 home apg(7) colophon feed

% A “One” Line Echo Server Using “let” in Python % python, hacks, whyohwhy, #pinned % 2014-11-12

This morning I realized something incredibly stupid. Stupid, because it has no real value except as a curiosity–which is to say, its perfect for this blog, which has featured other, things, of a similar nature.

Anyone familiar with Python and functional programming, will lambast Python for its measly one-line anonymous functions. What if they could do more? Well, they can! And, they can even introduce lexically scoped bindings as one would get if they had just used a better language to begin with, all in a “somewhat”1 nice, easy, and clean way.

I present to you, a one-line2 echo server that will eventually exhaust all of your memory, and slow to a crawl…

import socket
import itertools

(lambda port=9000, s=socket.socket(socket.AF_INET, socket.SOCK_STREAM):
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) == None and 
      s.bind(('', port)) == None and
      s.listen(5) == None and
      list(map(lambda c:
                  c[0].sendall(c[0].recv(1024)) and
               (s.accept() for _ in itertools.count(1)))))()

Wait, what? Yeah. Something special, isn’t it? There’s a lot going on here, so let’s break it down a bit.

lambda port=9000, s=socket.socket(socket.AF_INET, socket.SOCK_STREAM):

This is the best part of the trick, and the reason I threw in “let” in the title. In lexically scoped languages, such as Scheme, it’s common to see the use of the let form which introduces new bindings that are lexically bound, i.e., local to the body of the let expression. These are isomorphic to “block-scoped” variables one might find in other languages.

(let ((port 9000))
   <some body>)

In Scheme, the above let defines port only within <some body>. That construct is isomorphic to the following Scheme (and in fact many implementations just macro expand let into this):

((lambda (port) <some body>) 9000)

We utilize default arguments to assign names to values in the Python version, and exploit the fact that a lambda by itself doesn’t bind to a name as def does3, and doesn’t commonly appear in the global scope. What this means is that our “bindings” are evaluated when the anonymous function is created, which means it’s safe to use within a loop, or some other nested scope.

This lambda perversion, therefore, is isomorphic to the following Python:

(lambda port: <utilize port somehow>)(9000)

Now, that we’ve established this baseline, let’s move on.

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) == None and 
s.bind(('', port)) == None and
s.listen(5) == None and

Here, we exploit the fact that the and operator evaluates all of its operands provided they return truthy values. Since these functions return None, we just check to see if they returned None and continue to the next statement. This is of course roughly isomorphic to the following:

s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', port))

Simple enough.

Continuing on, we get to the trickiest part of it all:

list(map(lambda c:
             c[0].sendall(c[0].recv(1024)) and
         (s.accept() for _ in itertools.count(1))))

Ignoring the outer list for now, we see a simple call to map, which maps the lambda over the values produced by the generator expression. The generator expression produces an infinite list connected sockets, but since s.accept() blocks until a client is connected, this implements a typical listen-accept loop. The roughly isomorphic, plain ole Python looks like so:

while True:
    c = s.accept()

Why roughly? Because map is lazily evaluated, and produces a new generator. We need a forcing function in order for each connected socket to be applied to the lambda we have passed to the map call. Enter list which does that beautifully, though ensures that we’ll eventually completely exhaust memory if we accept a lot of connections. That list being generated will store the value None for every client that exists.

The only thing left to do is invoke our echo server, by wrapping () around the lambda and tacking on () to call it.

Update: trousers suggested that a set comprehension could avoid the catastrophic unbounded memory problem present with the call to list. No set comprehension, however, should be necessary if we just instead change list to set.

  1. As in “sort of,” if you ignore the extra (), the and connector, and all the other little gotchas… 

  2. … and 2 imports 

  3. There’s nothing about this trick that won’t work with def by the way, and the following decorator eliminates the need for immediate calls which we must do in the pure lambda method: let = lambda func: func() and func