A Declarative Clock in Eve

Corey Montella - 21 Jul 2016

A clock example is pretty much the “Hello World” of reactive applications. It’s got all the right pieces: some event stream which changes over time, and a way to present those changes visually. Here is our version:

A Clock in Eve

This clock is written in the Eve developer syntax, which is proposed in our first Request for Comments (RFC). In this post, I’ll go through the code and explain how it works.

Eve code

Eve code is written as a series of blocks, each of which can be thought of as operating in two phases:

  • Phase 1: Collect objects from the Eve DB
  • Phase 2: Mutate objects in the Eve DB

This pattern repeats in each of the blocks. The clock program consists of two blocks: the first generically defines a clock hand, while the second defines the clock itself. Let’s focus on each block in turn.

Draw a clock hand

draw a clock hand
 // Select all the clock hands
 hand = [#clock-hand angle length]

 // Eve will maintain the following objects
 maintain         

    // Calculate x1, y2, x2, y2 for each hand
    hand := [#line, x1: 50, y1: 50,

            // using angle and length
            x2: 50 + (length * sin(angle)),
            y2: 50 - (length * cos(angle))]

Blocks themselves have a structure. Any line indented at least once is treated as code, while any line with no intention is treated as a comment. This has the nice effect of being able to write documentation about the functionality of the program, with code blocks interspersed throughout. The rest of the block follows the collect -> mutate pattern.

In the collect phase of the block, we gather all the objects we need from the Eve DB. In this block, the collect phase is a single line, where we find our first object:

hand = [#clock-hand angle length]

Objects are a set of attribute:value pairs enclosed in square brackets. They ask Eve to find all the entities that match the supplied attribute shape. The hand object here is asking Eve to find every object tagged #clock-hand that also has the attributes angle and length. Since we’ve just given the name of the attributes here, we can use them as variables later in the program e.g. sin(angle).

Now we enter the mutate phase of the query, indicated by the use of the maintain fence. This fence says that we are finished reading from the Eve DB, and now we are ready to write to it. The use of the maintain fence in particular says that as data changes, Eve will keep their dependant objects up-to-date. This is the first feature that enables the reactivity of the program (the clock hands change position as the time changes):

 hand := [#line, x1: 50, y1: 50,
           x2: 50 + (length * sin(angle)),
           y2: 50 - (length * cos(angle))]

Here, := is the set operator, one of three mutation opaertors (the other two being add += and remove -=). The set operator sets the attributes of the target object to the supplied values, overwriting any previous values on the attribute. Here, the attributes being set are the x1, x2, y1, and y2 coordinates of the clock hand.

That’s all this block does: it selects every #clock-hand, and tags each one as a #line, which Eve knows how to draw. In the next block, we define the clock as a clock face with #clock-hands.

Draw a clock

draw a clock
 // Select the current time
 [#time hours minutes seconds]   
                                     
 // Update the SVG as the time changes
 maintain        
       
    // Add an SVG element to the root of the DOM                                              
    [#svg viewBox: "0 0 100 100", width: "300px", children: 

     // Add a clock face at (50,50) with radius 45.           
     [#circle cx: 50, cy: 50, r: 45, fill: "#0B79CE"]  
           
     // Add the hours hand    
     [#clock-hand angle: 30 * hours, length: 30, stroke: "#023963"]

     // Add the minutes hand   
     [#clock-hand angle: 6 * minutes, length: 40, stroke: "#023963"]

     // Add the seconds hand  
     [#clock-hand angle: 6 * seconds, length: 40, stroke: "#ce0b46"]] 

The second block (as with all blocks) follows the familiar collect -> mutate pattern. For this block’s collect phase, we are selecting the #time object, with its attributes hours, minutes, and seconds. This object is just like any other, but under the covers Eve keeps it up to date as the system clock changes. Then Eve updates every object that depends on time and so on.

After the maintain fence, we draw some SVG:

[#svg viewBox: "0 0 100 100", width: "300px", children: ... ]

Since no parent is specified, the SVG element is attached to the root of the DOM. Next, we draw some elements inside of the SVG box by adding them as children. We add the clock face (a blue circle at (50,50) with radius 45):

[#circle cx: 50, cy: 50, r: 45, fill: "#0B79CE"] 

and three hands:

[#clock-hand angle: 30 * hours, length: 30, stroke: "#023963"]

This is where the current block ties back into the previous one. We’re adding an object with the tag #clock-hand and attributes angle and length. This is exactly the pattern we were matching against in the first block! Thus, the loop is completed, and the clock hands are drawn as lines based on the current time as an angle.

Try it yourself!

You can download Eve and try the clock yourself! The quickest way is to use our docker container: docker pull witheve/eve

But you can also download the Eve source and build it yourself: git clone https://github.com/witheve/Eve.git. Instructions to build are available on the witheve/eve repository.