Programming today involves editing code while also running it in our head. To augment this mental simulation, live programming promises for much more fluid feedback between the programmer and a program that is executing while it is being edited.
A PL designer used to be able to design some syntax and semantics for their language, implement a compiler, and then call it a day. Today, however, languages are supported by sophisticated environments that, when designed together with languages, have the potential to significantly improve the programmer’s overall experience.
One area that vastly benefits from language/environment co-design is code typography, which essentially defines the look and feel of code itself. This essay documents what I have done in my current YinYang prototype; I do not claim to be an expert and am simply trying to share my experience and obtain feedback.
This is the third in a series of essays on advanced programming environments; the first is on usable live programming and the second is on managed time.
Blocks
A language’s statement blocks syntax has huge implications to how code will be laid out. There are many different styles to consider, but the two primary ones are curly brace (C-style) or off-side rule (opens in new tab) (indented python-style). I had always been a curly brace person, but typographically, code should be indented anyways, and braces serve no real role. Indentation is also easy to bring out via side bars with minimal horizontal spacing consumed; consider:
There is also «expression only» Lisp-style syntax that lacks blocks; see A Few Examples of Lisp Code Typography
Side bars become progressively darker as the indent level increases (one level indent is barely visible). The side bar of the block that the programmer is in is highlighted. The environment auto-indents, preserving or increasing indent based on whether the previous line ends in colon; the programmer may increase or decrease indent manually as needed. Unlike Python, short one line blocks can be expressed after the colon as a form of syntactic brevity; e.g.
Taken from the current prototype; it is amazing (and scary) what can be done when writing an editor from scratch.
Parentheses
Although curly braces are not needed to express blocks, their parenthesis cousins are still needed encoding method calls and explicitly specifying precedence. Whereas blocks define vertical chunks, parentheses help define horizontal chunks. For this reason, when not being edited parens have cell-like renderings where commas are rendered bar delimiters. Consider:
The same line of code highlighted is shown when selected (top) and when not (bottom). When highlighted for editing, parentheses and commas are rendered as this is what the programmer would actually type or delete. However, when the line is not selected, an easier to read table-like rendering is used with a background that slightly darkens as the nesting depth increases.
What happens when parentheses are nested too deep? At 2.5% background, the cell goes black at about 40 nesting levels.
Operators
Unicode operators have been around for a while yet we do not use them much because they are hard to type. Rather than have programmers write directly in Unicode, YinYang supports Unicode renderings for plain-old ascii operators. Consider the ascii token «>=» that is rendered as «≥∙». Notice the little dot at the end: because the we actually write «>=», the rendering has to have two characters to permit editing; deleting the dot is equivalent to deleting the ‘=’ character, causing the token to render as «>». Unicode rendering occurs as the programmer writes ascii; consider:
var m = navigator.appName.toLowerCase().indexOf(«internet explorer») == -1;
var n = navigator.userAgent.toLowerCase().indexOf(«trident») == -1;
var nm = m && n;
if (nm)
{
var img1 = new Image();
img1.src = ‘https://www.microsoft.com/en-us/research/project/live-programming/?locale=fr-catp3.gif’;
}
The user firsts declares a new b variable using the $ symbol, which is rendered as §. The users then writes a > expression, appending = to form ≥∙, and then prepending ! to form ∙≱∙. The digits 10 are then appended to b, creating the rendering b10; YinYang will always render trailing digits in an identifier as subscripts. Finally, the user deletes the first and last dot of ∙≱∙ to go back to >.
Renderings are provided by visual and intent composition. As examples of the former, => is rendered as ⇒∙ and +++ rendered as ∙⧻∙ based purely based on visual composition, while ! is rendered to and intended Boolean negation ¬, but can also be added to many operators to derive ≯∙ (!>), ∙≱∙ (!>=), ≠∙ (!=), ⇏∙ (!=>), and so on. Note that the ∙ is only rendered on selected lines and is otherwise hidden.
Operators are rendered bold with a different color to prevent them from being confused with identifiers, which is especially important for multiplication (typed as * but rendered as ×); consider:
Even though x and × look very similar, the × operator stands out.
Presentation
Putting it all together, we get a presentation that is decent:
This code defines a Ball object whose position p and gravity g is parameterized by an enclosing mk method. Note that within the ball object, a method is defined using the Greek Δ, which is written as «D_». The code also contains some multi-part identifiers; underscores are used rather than rely on Camel case, but they are rendered as gray square dots (‘▪’) within the code for better readability.
Note also that extra spaces are added to the code to enforce alignment. Although a proportional font (Segoe UI) is used, spaces are of variable width so that they always end on a global alignment point. This allows programmers to align their code when they want to at the cost of variable width spaces that do not start from a globally aligned grid point.
Here is the code for the Ball trait:
From these images, note the use of color in YinYang: keywords, dots, colons, and dollars are colored bluish and are also bolder so they standout as landmarks. Constants are colored greenish while traits and methods are bolded as defined. We use color sparingly to prevent it from overwhelming the programmer, but we also have something better to use our color budget on.
For an alternative take on color usage, see Lamdu
Metatext
Metatext is automatically supplementary text that augments the source text with commentary about the program they are writing. In most programming environments, metatext is limited to error markers. YinYang, however, includes metatext directly in the programming environment to indicate syntax, type, and run-time errors as well as probe results; consider:
Metatext was coined in Design Principles for the Enhanced Presentation of Computer Program Source Text, which is also a good early source on this topic.
var m = navigator.appName.toLowerCase().indexOf(«internet explorer») == -1;
var n = navigator.userAgent.toLowerCase().indexOf(«trident») == -1;
var nm = m && n;
if (nm)
{
var img1 = new Image();
img1.src = ‘https://www.microsoft.com/en-us/research/project/live-programming/?locale=fr-catp6.gif’;
}
In this example, the programmer first defines «x», as they type they get various syntax and type errors in red; the programmer can easily ignore these and get a satisfying «nothingness» when they have completed the definition. After «x» is defined, they get a new error in orange: bar returns zero, so the division fails! Once they leave the line, the metatext disappears while the affected token remains underlined (only metatext for the selected line is shown). The programmer changes bar’s definition to eliminate the run-time error.
The programmer then defines «y» in much the same way. Once defined, the programmer can «probe» the value of expressions by prefixing them with an «@» symbol; this metatext then appears in purple. As definitions are changed in the program, «@» probing metatext changes in real time.
See the usable live programming essay for more information on probing.
Future Work
YinYang’s design is a work in progress. Not all of the decisions made will stand the test of time, and there are still many features to add. For one thing, YinYang only supports line breaks between block statements. Also, I have decided to heavily use proportional fonts in YinYang, but have no answer yet to the alignment problems that these bring; something like elastic tab stops are needed.
S’ouvre dans un nouvel onglet