There are two areas we have unsolved composability concerns in the triple scripts ecosystem:
- when a general purpose libpack that we link against is itself a valid triple script (we need to transform its shunting block; maybe this should be as simple as truncating the IIFE with a semicolon—replacing the invocation parens XXX 2023 March: Replacing the parens can be a problem for roundtripping, so consider instead a scheme whereby we (a) insert the semicolon as described, and (b) insert the token
`inert`immediately after the IIFE open paren—we need only delete those two tokens, which is "safer" than remove-and-resynthesize XXX when looking for these tokens, should the token stream be whitespace-sensitive? A: Probably; reject any inputs that don't match exactly the sort of output that the compiler produces.)
- distinct from the case of linking against an existing program for use as a lib, we want to be able to more-or-less contrive of a format that allows us to chain multiple programs together in a "pipe"
A use case for the latter: suppose program A only natively supports attaching to a file source via officially non-standard but reasonably widely supported APIs, but nonetheless the operator is kept from using A because they are forced to use a runtime where these APIs are not available. Program Z is written as a self-contained but mostly useless script that puts a text input on the screen meant to accepting the textual output of xxd or od (by way of the clipboard), attempts to reconstruct it into a buffer while assuming that it's a well-formed ZIP file, thus creating a read-only in-memory file system from the buffer, and then outputting a ZIP by default. We should offer a way to compose programs A and Z such that Z is given initial control, and then A is given control—being able to make use of Z's in-memory filesystem. Furthermore, keeping our use case in mind, whatever the process entails for linking A and Z into a single self-contained object, this should be trivial to do by hand, given only access to a dumb text editor and the compilation texts of A and Z.
(One approach is to exploit the fact that Z is authored with the a priori assumption that it will be used in this way, and simply design Z such that it accepts as a second textual input the program text for A--or any other valid triple script--analyzes A for conformance to a particular protocol, and then attempts to do its own chainloading internally. This is less than ideal that the "reified pipelines" approach described above.)
2021 November 01: Consider a third composability problem that is solved in Newspeak but not with triple script modules: we want to allow visualization of a program (say a compiler) with interactive diagrams and/or inspectors, and we opt to do this by subclassing the original components in order to constrain necessary changes to a separate "layer" that doesn't interfere in the vein of cross-cutting concerns with the original implementation. Subclassing *is* well-suited for this problem, except in one area: tight binding by name for dependency on another module.
Consider a parser and tokenizer for example, implemented by the classes `FooParser` and `FooTokenizer`. It may be the case that `FooParser` is implemented such that it is never responsible for instantiating the associated tokenizer, instead having it passed in at the constructor or later with the use of some other method, but it is also possible that `FooParser` will indeed attempt to manage its own tokenizer by importing `FooTokenizer` and instantiating it directly by name. While a subclass can easily hook implementation details of the original module (its superclass) at the method level by overriding that method and delegating to it, the language affords no easy opportunity for the surgical replacement in e.g. `VisualFooParser` of the instantiation (or use of static methods) of `FooTokenizer` from the original `FooParser`. In fact, the only way to do so would be to isolate any interaction that binds by name to a local (instance) method--don't instantiate `FooTokenizer` directly in the middle of some `FooParser` body, but instead call, say, `this._createTokenizer` which in turn does the necessary work. This is likely to be very annoying since it will result in dozens if not hundreds or thousands of stub methods that merely wrap the invocation of some other module constructor or static method...
Ideally, this would be solved at the language level a la Newspeak, but I fear the environmental constraints makes this a non-starter.