Skip to content
Writing Python without any statements*
Python
Branch: master
Clone or download

Latest commit

Latest commit 9a1c6a8 Feb 3, 2020

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode
.gitignore
README.md
expr.py
expr_test.py
http.py
http_server.py
http_test.py
is_prime.py
tcp_server.py

README.md

express-your-self

Python, with no statements!

Inside expr.py you'll find some utility functions and classes that let you write programs without any statements (barring a single import at the top of the file...).

I've written a (sort-of working) TCP server and an HTTP server.

Here's an example of the code you might write. This starts a mutli-threaded TCP server that simply echos whatever you send it. Try it out using netcat. (warning: it's a little broken)

from expr import *

# `do` lets use sequence "statements"
do([
    # "walrus operator" gives us variables (python 3.8+)
    socket := require('socket'),
    threading := require('threading'),

    spawn := lambda target, args: do([
        handler_thread := threading.Thread(target=target, args=args),
        setattr(handler_thread, 'daemon', True),
        handler_thread.start()
    ]),

    ends_with_newline := lambda bytes_: \
        len(bytes_) > 0 and bytes_[len(bytes_) - 1] == ord('\n'),

    handle_client := lambda current_connection, client_addr: do([
        print(f"client connected at {client_addr}"),
        # loop_while calls the provided lambda over and over, until the final expression is falsy
        loop_while(lambda: do([
            recvd_bytes := current_connection.recv(1024),
            current_connection.send(recvd_bytes),

            not ends_with_newline(recvd_bytes),
        ])),
    ]),


    listen := lambda host, port: do([
        connection := socket.socket(socket.AF_INET, socket.SOCK_STREAM),
        connection.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1),
        connection.bind((host, port)),

        # Listen for clients (max 10 clients in waiting)
        connection.listen(10),

        print(f"server listening on {host}:{port}"),

        loop(lambda: do([
            client_connection := connection.accept(),
            spawn(target=handle_client, args=client_connection),
        ]))
    ]),


    listen("localhost", 3000)
])

The code in http.py and http_server.py is much more interesting. Cool things not included in this snippet:

  • t is a way to get "data classes". You give it a name and a list of properties, as follows: Pair := t('Pair', ['one', 'two'])
  • Box is to get around the fact that we don't have mutable bindings. Instead of the binding being mutable, just stick it in a container!
  • klass, for when a data class isn't enough. Used to define Box:
Box = klass('Box', {
    '__init__': lambda self, value: setattr(self, 'value', value),
    'get': lambda self: self.value,
    'set': lambda self, setter: setattr(self, 'value', setter(self.value)),
})

improvements

  • Exceptions! There's no way to catch exceptions at the moment. It would be easy to write a helper function using try/catch statements, but that's cheating.
You can’t perform that action at this time.