Introduction to Eve

Introducing Eve, a modern relational language for writing data-driven programs without the boilerplate.

Tagged with: eve

Today we're going to look at getting started with Eve, described as "a modern relational language for writing data-driven programs without the boilerplate." It's a promising language that I've been following for quite a while now, and it has some interesting and unique properties. Let's get started.


We'll start by checking out the Eve website. It calls out a few high-level features of the language that are intriguing:

  • Instant feedback
  • Naturally documented
  • Designed for debugging
  • Concurrent and compositional
  • A single data model
  • Fits in your stack

Before we move on, let's install Eve.

git clone
cd eve-starter
npm install

Then we'll start the program switcher, which will show us all of the Eve programs in this project and allow us to pick one:

npm start

Let's start by looking at the counter.eve program. Click on it and you can see a few counters being shown. What does the code look like?

vim programs/counter.eve

It's a markdown file with embedded Eve blocks, delimited by ~~~. Eve programs tend to be written in a literate programming style, which is a fantastic thing to see happen from the early days of a project.

# Counter

This program demonstrates:

- responding to events
- drawing elements on the screen
- reusing elements programatically
- extending an element

### Increment a Counter

Each button uses the referenced counter to increment itself. We need to think about two tags to accomplish this goal:

- `#html/event/click` is a record created by the HTML watcher any time a user clicks somewhere within an Eve app.
- `#ui/button` is a record we'll create a little later on to represent our button. The UI Watcher will helpfully draw it as a graphical button for us.

  [#html/event/click element: [#ui/button diff counter]]

  counter.count := counter.count + diff

### Build a Counter

For every `#counter`, we create a `#ui/row` that contains the elements that draw the counter. These rows are added automatically to the root of the DOM, but you could add them to a particular element instead adding them as children to the parent's record.

  counter = [#counter count]

  [#ui/row counter sort: counter.sort style: [flex: "0 0 auto" width: "100px"] children:
    [#ui/button text: "-" diff: -1 counter]
    [#ui/text text: count counter style: [padding: "0 6px" flex: 1 text-align: "right"]]
    [#ui/button text: "+" diff: 1 counter]]

Add some counters programatically. To make `n` unique and independent counters, we need to add something to the committed counter that makes it unique. Since `sort` = `{1, 2, 3, 4}`, when we add it to the counter record we get 4 different counters. As an added bonus, we can use it to choose what order to display our counters in. We also add one `#fancy` counter, which is a standard counter with new styling.

  sort = math/range[start: 1 stop: 4]

  [#counter sort count: 0]
  [#counter #fancy sort: 5 count: 0]

### Extend the Counter

This block says: "For every rows with a counter that is tagged fancy, add a style with a black background and pink text". Let's break it down. We search for all `#ui/row`s with a counter attribute. The counter is constrained to be only counters with a `#fancy` tag. Then we bind a new style to each.

  container = [#ui/row counter]
  counter.tag = "fancy"

bind += [background: "black" color: "#FFD0E0"]

I'm not going to work through this right now, but I wanted to call it out as a good introduction. Let's make our own program:

vim programs/helloworld.eve

Here, we'll create a markdown file that works through the quickstart tutorial:

# Hello World

Eve is based on the concept of a single data store that you can search in and
commit to. Let's start by committing a record:

  [#greeting message: "hello world"]

Here we're committing a record with the tag `greeting` and a field `message`
containing the string `hello world`. Tags are used to specify groups of related

We can search for records. Let's search for this record and display it on the

  [#greeting message]

  [#ui/text text: message]

Here we've created a new record. It's tagged with `#ui/text`. The Eve runtime
will search for records of this type and display them on the screen.

That should be enough to see something in the browser. Let's open our program at http://localhost:8000/app/eveRoot/helloworld.eve.

We can see the message on the screen. Let's commit a new greeting record now and see what happens:

A search might return multiple records. We'll add a new record and see it

  [#greeting message: "howdy world"]

We can see that now there are two #ui/text records committed, and both are displayed. Eve blocks will automatically react to their bound records being changed. We saw this happen by committing a new greeting after the block that searched for and rendered them. We can use this to create a simple clock.

Eve blocks react to changes in the data store automatically. Let's take
advantage of this to add a clock:

  [#time #system/timer resolution: 1000]

Here we're committing a new record tagged with `time`. It uses `#system/timer`
to create a timer that updates each second. Let's display it on the screen:

  [#time second]

  [#ui/text text: second]

This time we're just binding a record. This is different than committing them,
as this record won't persist until explicitly removed.

Next, we'll add a button and count how many times it is clicked:

We can commit a `ui/button` record to draw a button on the screen.

  [#ui/button #increment text: "+1"]

Now this button will be an element of type `increment` containing the text `+1`.
We will search for click events on this element and commit each click event to
the store:

  event = [#html/event/click element: [#increment]]

  [#clicked event]

Here, we're finding all clicks on our `increment` elements, and committing a
record for each click.

Now our store contains a `clicked` record for each instance of us clicking on
the button. We can count these with the `gather/count` function, then bind a
text element that displays the result:

  how-many = gather/count[for: [#clicked]]

  [#ui/text text: "The button has been clicked {{how-many}} times"]

Here we can see how to interpolate a value inside of a string. That's it for the basic tutorial.


In today's episode, we installed an Eve starter project and worked through the introduction for Eve, explaining it as we went. I'm really excited by Eve and I hope you'll play with it a bit. If you build something cool with it, please reach out in the comments to let me know. See you soon!


login to comment
  1. Comments for Introduction to Eve