Swift Playground Technical Design

24 Jun 2017


This post is a high level, end to end, summary of playground design in The Swift Programming Language and how playgrounds manifested into Vim.

I recently became obsessed with playgrounds and the possibilities they could unlock for my development runloop. To play Swift in Vim meant to write up a prototype and learn some things.

Playgrounds are an interactive way to write a program and visualize program state side by side with the actual program. They can speed up the development runloop and make programming more fun.

Playground

Working prototype of a Swift playground environment in Vim

Language Level Interface

Language support is required to visualize program state as it happens.

Playgrounds are integrated into the language in a way that is elegant, encapsulated, and easy to extend.

At the front end level, playground specific function calls are inserted into the provided Swift code ( like Playground.playground/Contents.Swift ).

When the user specifies the playground frontend option ( -Xfrontend -playground ), calls to the playground runtime are inserted.

In the compiler, it’s implemented via the inclusion of the playground transform. The playground transform searches the AST for relevant usages, like variable assignments, and print calls, and then inserts the playground calls.

The Swift compiler integrates many abilities through transforms, which is an excellent pattern. The complexity of playgrounds is encapsulated: it doesn’t leak to the rest of the compiler.

Playground Runtime

The actual playground logic is specified by the user; not the language implementation. Playground logic is provided to Swift through an interface which is a set of builtin functions: the Playground Runtime.

These builtin functions are undefined in the Swift standard library. A user provides these functions to Swift; a Playground Runtime must be linked into the final playground executable.

Here are a few key functions in the builtin API:

/// Return an object to the system representing the print invocation
func $builtin_postPrint(_ sl : Int, _ el : Int, _ sc : Int, _ ec: Int) -> AnyObject?
       
/// Send data ( for example write to StdOut, or XPC )
func $builtin_send_data(_ object:AnyObject?)

For a program like an IDE, an implementation of these calls could notify the editor about output. For a basic playground implementation, like SwiftPlayground.vim, the implementation of these calls simply writes to standard out.

Execution

To see the output of the playground, the compiled playground executable is executed. Playground Runtime ( Logging ) calls are executed with the provided code.

For a given target system, like a playground on the Mac, the implementation of execution could be as simple as running the binary. In vim, it is this trivial

A common case is to run iOS based playgrounds. Conveniently, Apple provides an API to run processes on a Simulator in performant fashion. See ( simctl spawn ) for more information.

Other Considerations

Editor Integration ( in Vim )

There is a thin layer between the playground and Vim: a protocol format to write logs and a corresponding parser.

When the user saves a playground buffer, the playground is compiled, executed, and the result is parsed in. Program output is mapped to a buffer.

Hooks for playgrounds are implemented via Vim’s event observing API, autocmd. Additionally, when the user scrolls, the playground buffer is synchronized with the main buffer.

Other Editor Features

Autocomplete and real time code diagnostics ( warnings and errors ) are implemented through iCompleteMe.

Syntax highlighting is available through Swift syntax definitions.

UI Development

For UI development, it could be interesting to display an interactive UI with the elements inline: rendering and interacting with UIViews or UIViewControllers.

Setting up a corresponding UI is a tangentially related work. This requires integration at the UIKit/AppKit level ( and currently, setting some state in PlaygroundSupport ).

Xcode already has implemented this feature inside of a slick UI. Apple open sourced some of the Xcode support which looks highly reusable.

Linux

It’s worth noting that Swift playgrounds can theoretically work on Linux, since at the language level, it boils down to an AST transform.

Conclusion

Playgrounds are onto something big. I think, they are a major selling point for Swift.

World class engineering decisions ( on Swift’s end ) made it easy and fun to implement Swift Playgrounds. To get playgrounds in Vim, I just connected the dots. Basically, trivial stuff on my end.

The entire Vim setup in the demo video is achievable with a few plugins:

I am interested in learning about and experimenting with effective development technologies like Playgrounds. Follow along and send issues ( and ideally PRs ) over at SwiftPlayground.vim and iCompleteMe.

Acknowledgements:

Thank you Swift team for implementing this API and opening it up! It’s fun to play around with Apple related technologies and I think open source IDE features are key for Swift.

Published on 24 Jun 2017 Find me on Twitter!