Embedded Literal Objects

When a PL is designed for a text editor, it is natural that text is the richest embedded literal. The text editor provides the visualization and update HCI. And text can certainly be useful; beyond modeling a subset of human input or output, it can model embedded DSLs such as regular expressions. But text is ineffective for many kinds of data we might wish to express in our programs – e.g. 3D meshes, logos, diagrams, graphs, grammars, matrices, decision trees, scene graphs, sound models, stage data in a 2D video game, dance notation, skeletal animation, spreadsheets, and so on.

Conventionally, to work with these richer models requires we use external tools – e.g. Maya, Blender, Photoshop. However, use of separate tools has many disadvantages, such as poor support for abstraction, partial evaluation, integration. It can also be inconvenient to load separate tools for a quick peek or edit.

A few not-so-conventional languages, such as pure data [more], are designed for work on a canvas and provide support for diagrams as literals. And then there are fully interactive programmable systems, such as Croquet project, where we manipulate first-class objects. The latter has advantages for flexibility and programmability, but also disadvantages with respect to entangling the code with the runtime.

I’ve been interested for a while in supporting flexible literal types for my Awelon project. Last week, my I was inspired towoard a simple model that I call embedded literal objects (ELO). An ELO is effectively just a block with some conventions surrounding it for display and update, leveraging edit-time computation. Relevant bullets:

  • represented by block of pure bytecode embedded in source code
  • fixpoint closure type, e.g. `µELO.{query: Q→R, update:U→ELO}`
  • commands are either updates or queries
  • IDE processes updates with ELO and writes resulting ELO into source code
  • queries can obtain menus of command, rendering to canvas, access data
  • development of commands and queries left to convention

Like text literals, an ELO can be copied and pasted, version controlled, and readily reused or re-edited across projects. There is no entanglement with the program context. Unlike text literals, an ELO potentially has much richer structure for easy composition, decomposition, and abstraction. We’re likely to develop ELOs that measure many megabytes in size. Though, a lot of redundant logic, e.g. for command menus, rendering, could be compressed via bytecode-layer linking model.

For current Awelon project languages, the proposed serialization of ELOs is quite trivial:

〚raw awelon bytecode here〛          in AO
[raw awelon bytecode here]{&elo}l   in ABC

The dedicated syntax for ELOs in Awelon Object (AO) language helps the IDE recognize them for special treatment. I’m using the unicode white variant square brackets: U+301A and U+301B. The resulting bytecode is just a plain old block with an extra annotation `{&elo}` indicating its nature for bytecode level debuggers or extraction.

I love the idea that, modulo partial evaluation, these ad-hoc literal objects remain recognizable at the Awelon Bytecode (ABC) layer. This is valuable for both debugging and extraction at the bytecode layer, and also is consistent with ABC’s existing approach to pseudo-literal numbers (e.g. `#42` is a sequence of three bytecodes that generate the number forty-two on the stack) and embedded text (shorthand for a list of small integers). When programs fall to pieces, comprehension starts at the bedrock, which for Awelon project is ABC. Every little bit of consistency, simplicity, transparency, and legibility at the bytecode level will help developers.

A new ELO could easily be generated from the AO dictionary as it stands. An AO IDE might also provide a menu of ELOs by searching for words starting with prefix `elo.`.

Processing ELOs

For text-based embedded DSLs, we typically use a command to interpret or compile the text. For example:

"x y z → y^2 + x^2 - |y|" doTheMath

Of course, text works well for only a small subset of DSLs, such as regular expressions. Math really isn’t among them if we want rich symbology, matrices, big division bars, and so on. An Awelon system can potentially optimize this behavior by systematic application of partial evaluation, i.e. such that we do not process the string on every execution.

With ELOs, we have greater flexibility. An ELO has its own logic, data, and can represent both rich and abstract data structures. We might ask an ELO to compile itself, or extract a value, or query a specific field, or to render itself at runtime. An ELO exposes the exact same set of commands to the runtime as it does to the IDE. ELOs can be treated as simple values, copied as many times as needed.

Updating ELO Types

Individual ELOs can be updated via the available commands. But how do we update the set of commands? For example, if we have an ‘image’ type with a canvas and a bunch of editing commands, how do we add new brushes and commands? I can think of several approaches:

  1. extensible command set: ELO command sets may be extensible and replaceable by convention, via specific commands
  2. explicit import/export: ELOs may provide an ‘export’ command that is readily imported by the next version of the ELO
  3. adapter pattern: wrap the ELO in an adapter that can translate commands and responses, at cost of performance
  4. extract from ELO: bring debuggers to bear on upon the bytecode and surgically extract the information we care about.
  5. extract from history: record commands that updated an ELO, and replay them on the new version of the ELO
  6. IDE layer extension: recognize common ELO types (e.g. based on query for type info) and install command sets at IDE layer

I suspect the answer to the ELO type update problem will be some ad-hoc mix of all of the above. The first two are preferable, and are ultimately achieved through convention and best practices in ELO design. The adapter pattern isn’t ideal, but can work well enough if not layered too deeply. The last few lean heavily on the integrated development environment, but might serve as effective fallbacks. Having a history of commands on ELOs would be useful anyway for extracting user macros into reusable subprograms.

In any case, the update problem is analogous to modifying text literals for an embedded DSL after a language version update. Developers will systematically update all instances until they get bored of doing so and start designing with forward compatibility in mind. At that point, they’ll update only the literals that need updating. Likely, there will be a recognizable ELO maturation life cycle.

The Way Forward

At the moment, my Awelon Object language is still trapped in a text editor, and ELOs won’t do me much good.

My intention is to eventually upgrade to editing code via a web browser, perhaps in a wiki-like environment. ELOs aren’t my only goal; I’m also interested in hyperlinks, live programming, automatic visualization of the tacit environment (perhaps from live tests), interactive documentation (tutorials, etc.), and so on. I think ELOs will become much more viable in such an environment.

There are a lot of details remaining. For example, I’ll want to develop an API for rendering to canvas, possibly inspired from HTML or SVG. Animations and sound are interesting areas for literals; I’d love the ability to ‘hear’ whatever sound model I’m looking at, or see animations running in a loop. For 3D or larger 2D structures, ability to rotate, pan, zoom, etc. could be useful.

This entry was posted in Language Design, Modularity, Types, User Interface, UserInterface. Bookmark the permalink.

5 Responses to Embedded Literal Objects

  1. Pingback: Code is Material | Awelon Blue

  2. Pingback: Wikilon Filesystem | Awelon Blue

  3. Pingback: Extensible Syntax for Awelon Project | Awelon Blue

  4. Pingback: Structure Editors for Wikilon | Awelon Blue

  5. Pingback: Wikilon Dictionary Applications | Awelon Blue

Leave a comment