Archive for software-development

a faster Morphic with morphic.js

Posted in Appsterdam, consulting, Context, Naiad, Smalltalk, Spoon, SqueakJS with tags , , , , , , , , , , on 28 June 2017 by Craig Latta

Google ChromeScreenSnapz017

Caffeine is powered by SqueakJS. The performance of SqueakJS is amazingly good, thanks in large part to its dynamic translation of Smalltalk compiled methods to JavaScript functions (which are in turn translated to machine code by your web browser’s JS engine). In the HTML5 environment where SqueakJS finds itself, there are several other tactics we can use to further improve user interface performance.

Delegate!

In a useful twist of fate, SqueakJS emerges into a GUI ecosystem descended from Smalltalk, now brimming with JavaScript frameworks to which SqueakJS can delegate much of its work. To make Caffeine an attractive environment for live exploration, I’m addressing each distraction I see.

The most prominent one is user interface responsiveness. SqueakJS is quite usable, even with large object memories, but its Morphic UI hasn’t reached the level of snappiness that we expect from today’s web apps. Squeak is a virtual machine, cranking away to support what is essentially an entire operating system, with a process scheduler, window system, compiler, and many other facilities. Since, with SqueakJS, that OS has access to a multitude of similar behavior in the JavaScript world, we should take advantage.

Of course, the UI design goals of the web are different than those of other operating systems. Today’s web apps are still firmly rooted in the web’s original “page” metaphor. “Single Page Applications” that scroll down for meters are the norm. While there are many frameworks for building SPAs, support for open-ended GUIs is uncommon. There are a few, though; one very good one is morphic.js.

morphic.js

Morphic.js is the work of Jens Mönig, and part of the Snap! project at UC Berkeley, a Scratch-like environment which teaches advanced computer science concepts. It’s a standalone JavaScript implementation of the Morphic UI framework. By using morphic.js, Squeak can save its cycles for other things, interacting with it only when necessary.

To use morphic.js in Caffeine, we need to give morphic.js an HTML5 canvas for drawing. The Webpage class can create new DOM elements, and use jQuery UI to give them effects like dragging and rotation. With one line we create a draggable canvas with window decorations:

canvas := Webpage createWindowOfKind: 'MorphicJS'

Now, after loading morphic.js, we can create a morphic.js WorldMorph object that uses the canvas:

world := (JS top at: #WorldMorph) newWithParameters: {canvas. false}

Finally, we need to create a rendering loop that regularly gets the world to draw itself on the canvas:

(JS top)
  at: #world
  put: world;
  at: #morphicJSRenderingLoop
  put: (
    (JS Function) new: '
      requestAnimationFrame(morphicJSRenderingLoop)
      world.doOneCycle()').

JS top morphicJSRenderingLoop

Now we have an empty morphic.js world to play with. The first thing to know about morphic.js is that you can get a world menu by control-clicking:

Google ChromeScreenSnapz018

Things are a lot more interesting if you choose development mode:

Google ChromeScreenSnapz019.png

Take some time to play around with the world menu, creating some morphs and modifying them. Note that you can also control-click on morphs to get morph-specific menus, and that you can inspect any morph.

Google ChromeScreenSnapz020.png

Also notice that this user interface is noticeably snappier than the current SqueakJS Morphic. MorphicJS isn’t trying to do all of the OS-level stuff that Squeak does, it’s just animating morphs, using a rendering loop that is runs as machine code in your web browser’s JavaScript engine.

Smalltalk tools in another world, with Hex

The inspector gives us an example of a useful morphic.js tool. Since we can pass Smalltalk blocks to JavaScript as callback functions, we have two-way communication between Smalltalk and JavaScript, and we can build morphic.js tools that mimic the traditional Squeak tools.

I’ve built two such tools so far, a workspace and a classes browser. You can try them out with these expressions:

HexMorphicJSWorkspace open.
HexMorphicJSClassesBrowser open

“Hex” refers to a user interface framework I wrote called Hex, which aggregates several JavaScript UI frameworks. HexMorphicJSWorkspace and HexMorphicJSClassesBrowser are subclasses of HexMorphicJSWindow. Each instance of every subclass of HexMorphicJSWindow can be used either as a standalone morphic.js window, or as a component in a more complex window. This is the case with these first two tools; a HexMorphicJSClassesBrowser uses a HexMorphicJSWorkspace as a pane for live code evaluation, and you can also use a HexMorphicJSWorkspace by itself as a workspace.

With a small amount of work, we get much snappier versions of the traditional Smalltalk tools. When using them, SqueakJS only has to do work when the tools request information from them. For example, when a workspace wants to print the result of evaluating some Smalltalk code, it asks SqueakJS to compile and evaluate it.

coming up…

It would be a shame not to reuse all the UI construction effort that went into the original Squeak Morphic tools, though. What if we were to put each Morphic window onto its own canvas, so that SqueakJS didn’t have to support moving windows, clipping and so on? Perhaps just doing that would yield a performance improvement. I’ll write about that next time.

Advertisements

Tether: remote messaging between Smalltalks with WebSockets

Posted in Appsterdam, consulting, Context, Naiad, Smalltalk, Spoon with tags , , , , , , on 30 October 2016 by Craig Latta

In my previous post, I introduced a new topology for distributed computation with Smalltalk: an object memory in SqueakJS in a web browser, paired by remote-messaging connection with another object memory in Cog in a native app, and connected with other SqueakJS/Cog pairs on other physical machines. The remote-messaging protocol that the memories speak is called Tether. I’ll go into a few details here.

passive frame-based messaging with WebSockets

We begin with a major constraint imposed by running in a web browser: we’re sandboxed, unable to listen for network connections. We must initiate a remote-messaging conversation by connecting to a listening server on a traditional operating system. Over the last few years, the W3C WebSockets standard has received widespread support in every major web browser. We can rely on the ability to create JavaScript WebSocket objects with the SqueakJS JavaScript bridge, and we can easily implement the WebSocket API in Smalltalk on non-web platforms using normal TCP sockets.

WebSockets use callback functions to deliver messages, or frames of bytes, between conversants. The Tether protocol imposes a structure on those bytes, which are processed on each side of the connection by instances of class Tether. The first four bytes are a 32-bit tag which indicates the Smalltalk class which should interpret the rest of the frame. In the case of a remote message, this is class Tether. Successive bytes indicate the message selector to perform, the receiver of the message, and the message parameters.

The message receiver is expressed as a 32-bit key into a table of exposed objects, maintained by the Tether instance handling the connection. The Tether instances themselves expose their identities to each other at the beginning of the conversation. Objects that aren’t specified by reference to an exposed-object table (such as message selectors) are expressed through serialization.

live serialization

The fact that both sides of the conversation are objects in live Smalltalk systems affords many optimizations that aren’t possible when serializing objects to a static file. For this reason, I call this live serialization. For example, when transferring a compiled method between systems, if the method’s literals are objects which already exist in the receiving system, we may write references to them rather than serializing them.

We can also take special measures when the receiving system is missing the classes whose instances we want to transfer. Instead of assuming in advance that the receiving system lacks the classes whose instances we’re transferring, and including them in our payload, as a static serialization file would, we can transfer such classes only on demand. This yields much higher accuracy in object transfer, and far fewer bytes sent over the wire. Since live serialization is part of a complete remote messaging protocol, any messages at all can be sent from either side to complete an object transfer.

With a receiver, selector, and parameters specified, the receiving system can perform the message sent from the sending system. Each object in the system is responsible for serializing itself over a Tether. If the answer to the remote message is a literal object, like a symbol or integer, it will write the bytes of its value on the Tether instance handling the message. If the answer isn’t a literal object, by default it will write a reference to itself. Developers can choose to pass objects by value or by reference as they see fit.

scheduling

Tether performs every remote message in a distinct process, so that no system blocks waiting for an answer to be sent back over the network. Each remote message-send is assigned a unique identifier, and each answer is sent with the ID of its message-send as metadata, so that it can be delivered to the correct waiting process.

This scheme extends the traditional imperative messaging semantics of Smalltalk to any number of machines, and each message-send may involve receiver and parameter objects which are all on different machines. Every message-send may invoke any number of further remote messages before answering.

transparent proxies

An object which represents an object on a remote system is called a proxy. Ideally, it forwards every message sent to it to the remote object, and so provides the illusion of transparent remote messaging. Remote messaging in Smalltalk is often done by using a proxy class which inherits and implements as few messages as possible, and overriding the handler message sent by the virtual machine when a message is not understood. This provides enough coverage to do many useful things, but some messages handled specially by the virtual machine are not forwarded. Some use cases, like remote debugging, require forwarding even those special messages.

To achieve total forwarding coverage, we must modify the virtual machine. There are some situations where this is undesirable (e.g., a lack of tools or expertise, or a requirement to use a past virtual machine unmodified). Tether uses the “does not understand” tactic above in these situations, but provides a modified virtual machine for the rest. In this virtual machine, message forwarding is triggered during method lookup for instances of a specific proxy class (which can be located anywhere in the class hierarchy). Method caching and methods implemented directly as virtual machine instructions are also appropriately adapted. There are a few messages which proxies must understand locally, to participate in live serialization. These messages are also handled specially by the virtual machine.

see for yourself

Tether is an integral part of the Context project from Black Page Digital. A demo of remote messaging between SqueakJS and Cog is available. In tomorrow’s post, I’ll discuss an everyday application of remote messaging.

 

Suspend in the browser, resume on the desktop.

Posted in Appsterdam, consulting, Context, Naiad, Smalltalk, Spoon with tags , , , , , , , , on 29 October 2016 by Craig Latta

In yesterday’s post, I showed how Bert Freudenberg’s SqueakJS can extend Smalltalk‘s traditional host platform integration for the web, with DOM access through my class ThisWebpage. With this we can build any front-end HTML5 webapp behavior that any other JavaScript framework can. Another thing we can do with ThisWebpage is install the native-app version of Squeak, giving us the full speed of Eliot Miranda’s Cog virtual machine.

Running Smalltalk on the web is a satisfying thing, but there are times when you need more speed or host operating system access than JavaScript in a web browser can provide. Eventually, we’ll be able to embed native code in web browsers using WebAssembly, which will be a big improvement. Even then, though, there will still be the platform access compromises that come with a sandboxed web environment. So, one obvious thing to do with our JavaScript access is move our Smalltalk processes to the desktop, where we can use the high-performance Cog virtual machine.

platform portability

Smalltalk is an image-based system. In addition to modeling an idealized processor, with its own instruction set, the Smalltalk virtual machine models the processor’s memory. The virtual machine can make a snapshot of this memory, as a normal host platform file called an image. This snapshot captures the complete execution state of the Smalltalk system (the object memory), including the program counters of every process that was running at the time. The virtual machine can also resume this snapshot, restoring that system state so that the system may continue. This is similar to the “sleep” function of a laptop.

Since the virtual machine provides a consistent platform abstraction above whatever host is running it, we can suspend the system on one host and resume it on another. Smalltalk programmers have taken great advantage of this for years, writing single systems which run on multiple operating systems (e.g., Macintosh and Windows). Java attempted to provide consistent execution semantics, under the tagline “write once, run anywhere” (with mixed results), but this did not extend to a continuous memory image. We can make an object memory snapshot with SqueakJS in a web browser, and resume it with Cog in a native app.

exporting ourselves

SqueakJS uses the HTML5 “indexed database” feature for persistent storage, making it look like a normal filesystem. We can write a snapshot of the running SqueakJS system this way. We can then use ThisWebpage to download the snapshot to the user’s machine. We add a link to the document in which SqueakJS runs, and synthesize a click on it, invoking the download.

We also use ThisWebpage to detect the user’s host operating system, and download a platform-specific Cog installer. I’ve written installers for macOS, Windows, and Linux. Each one downloads the Cog virtual machine, installs a platform handler for “squeak://” URLs that runs Cog, and invokes a squeak:// URL that runs our snapshot. This URL encodes the name of the snapshot file, Cog parameters (such as whether or not to run the system headless), and a base64-encoded JSON dictionary of other parameters that the Smalltalk object memory can process.

making contact

Now our object memory is running both in the browser in SqueakJS, and in Cog as a native app. The current Black Page Digital object memory for Squeak connects the two with a remote-messaging network service. When the SqueakJS-hosted instance invokes the local one, it also forks a process that periodically attempts a remote-messaging connection. When the memory resumes on a non-web host, it starts a WebSocket-based server to provide remote messaging service.

With the two Squeaks connected, objects in one can send messages to objects in the other, creating a distributed system. The Cog-based system now has access to the DOM of the web browser through ThisWebpage in the SqueakJS-based system, and the SqueakJS-based system has unsandboxed access to the host operating system through the Cog-based system. In particular, SqueakJS can use Cog to run network servers, so one can create a distributed system from SqueakJS instances running in many web browsers on many machines.

In tomorrow’s post, I’ll discuss the remote messaging protocol in more detail. After that, I’ll introduce a distributed network service that takes advantage of it.

 

SqueakJS changes its world with ThisWebpage

Posted in Appsterdam, consulting, Context, Naiad, Smalltalk, Spoon with tags , , , , , , , , , , , , on 28 October 2016 by Craig Latta

a new platform

Since becoming a virtual-machine-based app, Smalltalk has integrated well with other operating systems, providing the illusion of a consistent unified platform. With the ascendancy of JavaScript, the common execution environment provided by web browsers is effectively another host operating system. Smalltalk runs there too now, thanks to Bert Freudenberg’s SqueakJS. So in addition to macOS, Windows, and Linux, we now have the Web host platform.

While all platforms expose some of their functionality to apps through system calls, the Web exposes much more, through its Document Object Model API (DOM). This gives Smalltalk a special opportunity to enable livecoded apps on this platform. It also means that Smalltalk can interoperate more extensively with other Web platform apps, and participate in the ecosystem of JavaScript frameworks, both as a consumer and a producer.

to JavaScript and back

The part of SqueakJS which enables this is its bidirectional JavaScript bridge. This is implemented by class JSObjectProxy, and some special support in the SqueakJS virtual machine. One may set Smalltalk variables to JavaScript objects, send messages to JavaScript objects, and provide Smalltalk block closures as callback functions to JavaScript. One may interact with any JavaScript object in the Web environment. This means we can manipulate DOM objects as any other JavaScript framework would, to create new HTML5 user interfaces and modify existing ones.

In particular, we can embed SqueakJS in a web page, and modify that web page from SqueakJS processes. It would be very useful to have a Smalltalk object model of the host web page. I have created such a thing with the new class ThisWebpage.

reaching out with ThisWebpage

I chose the name of ThisWebpage to be reminiscent of “thisContext”, the traditional Smalltalk pseudo-variable used by an expression to access its method execution context. In a similar way, expressions can use ThisWebpage to access the DOM of the hosting Web environment. One simple example is adding a button:

ThisWebpage
  createButtonLabeled: 'fullscreen'
  evaluating: [Project current fullscreen: true]

Behind the scenes, ThisWebpage is doing this:

(JS document createElement: 'input')
  at: #type
  put: 'button';
  at: #onclick:
  put: [Project current fullscreen: true]

Class JSObjectProxy creates JS, an instance of itself, during installation of the JavaScript bridge. It corresponds to the JavaScript DOM object for the current web browser window, the top of the DOM object graph. By sending createElement:, the expression is invoking one of the DOM methods. The entire set of DOM methods is well-documented online (for example, here’s the documentation for Document.createElement).

So far, ThisWebpage has some basic behavior for adding buttons and frames, and for referring to the document elements in which SqueakJS is embedded. It can also create links and synthesize clicks on them. This is an important ability, which I use in making a Squeak object memory jump from SqueakJS in a web browser to a native Cog virtual machine on the desktop (the subject of tomorrow’s post).

The possibilities here are immense. ThisWebpage is waiting for you to make it do amazing front-end things! Check it out as part of the Context 7 alpha 1 release.

 

concept: the active filesystem

Posted in Appsterdam, consulting, Naiad, Smalltalk, Spoon with tags , , , , , on 17 September 2012 by Craig Latta

The Spoon history memory’s embedded webserver presents the object memory as a WebDAV filesystem. Classes appear as directories, and methods appear as files in those directories. Developers can mount the filesystem so that it appears normally with the other volumes on their operating system. Because of this, they can also use familiar file-based tools like file browsers and text editors to interact with it. When a file is written with one of these tools, the corresponding method is compiled and installed in the running system. Other side effects can be associated with special locations in the filesystem; for example, when a special “do it” file is written, the expressions in it are evaluated and the answer is written to another special file.

This is an example of an active filesystem: a virtual filesystem with behavior associated with its typical operations. Since the WebDAV server is a Spoon app, we have complete control over the way a virtual filesystem interacts with a user. In particular, we can support commodity tools.

I’m making another active filesystem for the InnoViz project in Amsterdam. This one behaves as a general-purpose database. The class hierarchy still appears as directories, but the methods do not appear. Instead, each class can contain subdirectories representing queries on objects in the database. A query directory contains files indicating the code run by the query, and the objects answered by it. Since queries are just another part of the filesystem, they are persistent and can be reused in another queries by multiple authors. This enables a form of collaborative query.

Users need not be programmers in the traditional sense in order to interact with the database. For example, one may add a new object to the database by editing the another object’s file and saving it under a new name. Still, users who know how to write programs can also interact with the database with their favorite language, they only need to know how to read and write files.

I’m looking forward to finding more use cases for active filesystems…

%d bloggers like this: