Coding 2022-08-26

By Max Woerner Chase

I've been thinking a bit more about NABTO, and I realized that there's something I need to address entirely before anything remotely object-oriented enters the picture.

Here is a Hello World program in Koka:

fun main()
  println("Hello world!") // println output

Here is a Hello World program in Python:

print("Hello world!")

The Koka code has the println() call inside the main function, while the Python version has it at the top level of the module. In Koka, module-level code is analyzed and acted on at compile time, while in Python, it's executed when the module is imported at run time. This means that either we need to restrict which effects are permissible at the module level, or we need to allow imports in NABTO to potentially emit arbitrary effects, once.

Hm, that "once" makes something occur to me. The import statement in Python and the require() function in Lua are, due to the way they memoize their results, kind of like delayed values that immediately get forced.

Okay, it just occurred to me that I probably don't want to go down this road. If the importing module is responsible in any way for handling the effects from the module that it imports, then that means that the values in a module can depend on where it's first imported. That seems less than ideal to me. To counter that, there could be some kind of runtime service that handles the effects from importing a module. Suppose some user code wants to mess with the effect handling, though?

I don't know if I'm satisfied with this idea, but maybe if there were some kind of sandboxed execution facility, so that someone who wanted custom effect handling could "simply" create an object to emulate the runtime, and within that emulated runtime, imports would be done completely freshly.

I'm tempted to see if the syntax could be made to support Lua's function call syntax, so that there's just a function instead of a statement. If this were a function, it would effectively only propagate errors and non-termination to the calling code, and all other effects would "pass through" the intervening layers to the runtime.

Final question to consider for tonight: does the fact that call trees all trace back to the __main__ module, combined with the ideas I've been going over, come together in a way that's elegant, inelegant, or pointless?

Well, let's look at the Hello World program for NABTO. It's going to be something like println("Hello World!") (probably with some boilerplate at the beginning). The runtime will import the module, and the import system will handle the text output effect. Then, it will finish with the module, and exit.

A more complex program will end up importing multiple modules, and suspending execution during the imports, then resuming, possibly with an error.

This all seems to make sense to me, but I really should sleep on it before I think I'm sure.

Good night.