write.as

Here's a quick writeup of why this idea is (luckily!) broken in multiple ways.

“What's important here is that the alice function doesn't maintain state.”

This merely turns variable usage into closure usage. You do not maintain state by means of using code + variables, you maintain state by means of using a closure-function + environment that the function is closed over. The closure-function is compiled code; the environment is state.

“Chris proposes that some programs may contain private data but at the same time be stateless”

This does not mean that the function is stateless; it means that state management is pushed away from expicit variables and into the language runtime + GC that will collect the closure's environment when it is no longer referenced.

    db = {
        'Alice': 'red',
        'Bob': 'blue'}

If you put db = {'Alice': 'red', 'Bob': 'blue'} in your source code, then it is indeed source code. If names and colors come from outside, then it isn't source code. Wrapping some user-provided data in a closure, similarly, doesn't magically turn it into code, or even source code.

Let's imply that I have the following AGPL program:

    (let ((x (read-from-network)))
      (lambda () (sleep 60) x))

This is its complete source code. It reads some stuff from the network (e.g. it makes a HTTP request), it sleeps for a minute, then it returns that data.

The thesis proposed by this post – that wrapping some data in a closure magically turns it into not just code, but source code, means that publishing the above snippet (that is the full source code of my program, I can run it, it will work!) is, for whatever reason, not enough; if I run this program, make a network call, fetch some data from the network, and then close the function (lambda () (sleep 60) x) over it, then it means that I must publish that data under the AGPL, since, for whatever magical reason, it stops being data and starts being source code.

This stupefying implication implies that closures, as a programming tool, become forbidden in all programming languages under AGPL if they refer to any kind of private data. Which is absurd.

Additionally, a closure is an instance of compiled code + environment. Environment is state/data; compiled code, which is the part that is affected by AGPL, is compiled from source code, which, in the above case, is (let ((x (read-from-network))) (lambda () (sleep 60) x)). AGPL never applies to program state, but to source code, since no one requires you to show e.g. the contents of all the Mastodon or Pleroma databases out there; therefore, it doesn't apply to the environment, which is program state, and only applies to the compiled code for the closure, and requires that the source code for that closure be published. And, by pasting the snippet of (let ((x (read-from-network))) (lambda () (sleep 60) x)) this requirement is satisfied.

Also, let's suppose that we have three programs that work in the identical way:

    (let ((x (read-from-network)))
      ((lambda () (sleep 60) x)))

    (let ((x (read-from-network)))
      ((lambda (y) (sleep 60) y) x))

    ((lambda (y) (sleep 60) y) (read-from-network))

The first program creates a closure that is then immediately executed. The second program and the third program invoke a function on some data fetched from some network. The second program has a temporary variable introduced, while the third doesn't.

Under the assumption made in this post, the first program must publish the value of X as it is source code, while the latter two programs are fine just as they are and don't need to publish X. Which is absurd.

One more addition: instantiating a closure doesn't mean creating any source code. If I execute (let ((x (read-from-network))) (lambda () (sleep 60) x)), no new source code is generated. If I execute it a hundred times, no new source code is generated either. In all sane language implementations, all that is generated are environment objects in memory containing user data and the actual user-facing stuff: closure objects that bind the single instance of compiled code to environment objects that contain data.

Yet another addition: closures and objects are equivalent, as taught e.g. by SICP. Therefore, if you ever create a structure or a class instance inside your program, you would therefore be required to publish the values of all fields inside that object. Therefore, OOP is now forbidden if you want to do anything that requires to not publish user data.