Boon

Timeless & Playful Language

noob or hacker, web or chip,
boon will guide your coding trip

First Look

1... 2... 3... every second
interval code

1... 2... 3... on a button click counter code

You can try out the examples on play.boon.run

Super Counter

raspberry pi and icesugar pro

pi and sugar diagram

What's on that diagram? Super counter!

  1. You press a button on the iCESugar dev board.
  2. The board sends a message to the Raspberry Pi.
  3. The computer increments the counter in its database.
  4. The board, the CLI (command-line interface), and the web app are notified that the counter value has changed.
  5. The board turns on the LED for a moment to signal that the counter has been incremented.
  6. The web app updates the rendered counter value and changes its color according to the defined script rules (e.g. green when the counter is less than 10, otherwise red).
  7. The CLI displays the new counter value and runs a configured command (e.g. show a notification or write something into the terminal/console).
  8. You can watch how data flows through the entire Super counter on the Monitor.

Flow Combinators

LATEST

LATEST code example

LATEST diagram

Math/sum diagram

WHILE

WHILE code example

WHILE diagram

WHEN

WHEN code example

WHEN diagram

THEN

THEN code example

THEN diagram

Summary

Real-world examples

  1. When the user presses Enter or clicks a send button in your chat application, use WHEN or THEN to copy the message written in the new-message input. With the WHILE combinator, you'd risk changing already sent messages with every change to the text input.
  2. Use WHILE to update texts in your multilingual application. With WHEN/THEN you'd update all dynamic texts only when the user decides to switch languages.

Durable State & Code Changes

Every program is a living organism, sooner or later you'll want to change its code but ideally not lose any data during the process or tell your users to not use your app during the weekend while you are "migrating data".

Let's say we want to upgrade our simple counter example - rename the variable counter to counter_2 and increment its value by 2 on a button click.

It would be a pretty straightforward operation, but we don't want to reset our counter value while deploying a new app version.

You can go to play.boon.run, click the button counter.bn in the header and follow the steps below with me.

NOTE: You'll write pipe operator ▷ by typing | and >. Boon Playground uses the JetBrains Mono font with enabled ligatures to combine them visually. I would also like to add support for infinite length ligatures to that font to have nice continuous lines for comments / dividers.

  1. Look at the original counter code, run it and press the + button to change counter state a bit. counter upgrade step 1
  2. Add the counter_2 definition, replace counter with counter_2 in HTML document items, and prevent the old counter from listening to button-press events. Notice old counter in counter_2's LATEST block to do the actual state migration from the old counter to the new one. Then run the example again. Nothing should change visually, but you're already using the upgraded app. counter upgrade step 2
  3. Remove the references to the old counter, delete its definition, and we are done! Run the example and click + to verify that it's incremented by 2. counter upgrade step 3
  4. When you want to reset the counter, click the Clear saved states button just above the preview pane on the playground to remove all states stored in the browser's LocalStorage, and then click the Run button to restart the app; the counter resets back to 0.

EXTRA: Variables in our playground examples are stored in the browser. However, the general idea is that some variables in your app will be stored in the browser, some variables in a standard database, and some of them nowhere to save memory or quickly forget things like passwords or tokens.

All roads lead to Rome document

counter flow diagram

Look at that counter example dataflow diagram again. Do all paths really lead to the document? Almost! The only exception is that blue LINK rectangle at the bottom left corner coming from the Element/button(..) function call.

What is that LINK good for? Why does it make the only loop in the entire diagram to ruin my otherwise perfect tree?!

Look at the counter code again:

counter code

  1. Notice the press: LINK object field being passed to the Element/button function call as part of the element argument.
  2. Function Element/button transforms the arguments into a data structure compatible with the element tree and digestible by the Document/new function.
  3. Boon browser runtime finds the global document variable and creates browser elements described in the passed element tree. When it finds event.press, it links it with events produced by those browser HTML/DOM elements.
  4. When linked, you can listen for new events with code like my_button.event.press |> THEN { .. }

So, for our current understanding, variable_name: LINK basically means that the variable's value can be set after the variable is defined - no other variables can be set once they are defined.

Finally, perfect trees!

We cannot really get rid of all loops in dataflow graphs - they are a natural part of programs and the things we do - we can only monitor them and try to remove accidental infinite loops.

However, look at this nice forest!:

counter state diagram

Enough diagrams! More code!

complex counter example

PASS + PASSED

Notice in the code above:

  1. root_element(PASS: store)
  2. FUNCTION root_element()
  3. PASSED.elements.increment_button

The only purpose is to pass data through multiple function calls without the need to mention them explicitly among function arguments.

Without PASS + PASSED, the same lines would look like:

  1. root_element(store: store) or store |> root_element()
  2. FUNCTION root_element(store) <- new function argument
  3. store.elements.increment_button

So PASS + PASSED is useful when you have deep function call tree (typically element tree) and bottom levels need something from top levels.

You already know what variable: LINK means and now you'll find out how to set it by yourself (instead of setting it by the Boon runtime).

Notice these lines:

  1. decrement_button: LINK
  2. counter_button(label: '-') |> LINK { PASSED.elements.decrement_button }

The element data returned from the counter_button(..) function call are linked to decrement_button and returned from LINK {} without any changes.

Where is Fibonacci??

fibonacci example

This idea was driven by design decisions to avoid recursions and keep loops as tight and hidden as possible. However, I want the Boon design to be driven by real applications, so I'll revisit this API/example when the need for channels, (infinite) streams, generators, lazy evaluation, tail recursions, or other related concepts emerges.

See the Problem, Fix the Flow

  1. A monitor/debugger is your friend. Have you ever played a Factorio-like game? I want to:

    • See the problem.
    • See statistics.
    • Be able to immediately fix the problem.
    • Want to know why the problem happened.
    • Want to see slow parts.
    • Want to see loops.
    • Want to see what is waiting and why.
    • Want to just watch and enjoy it while everything works as expected.
    • Want to be notified when something fails.

    Yes, you understand correctly, monitoring and a short feedback loop have high priority for Boon tools and design in general.

  2. A compiler is your friend. Nice error messages, fast type checking, hints.

error example

  1. A formatter is your friend. No need to think about the correct number of spaces. No confusing code diffs. Constant reading speed for a code reviewer.

Status & Future

A lot of things have to be implemented and explained, but the core is there and I don't plan to stop!

Examples on play.boon.run are guaranteed to run. I'll continuously add more there, and examples running outside the browser environment will appear as well.

Questions ▷ [email protected]

Credits