Glon - VID for the browser

This is the first time I’ve managed to get a Rebol-family application running in the browser in the form I actually wanted.

I did not want to reproduce the conventional web stack inside Rebol, nor build another PHP/Cheyenne-style templating system with bits of language embedded between angle brackets. Nor did I want to reimplement the whole browser GUI.

Instead, Glon implements only enough of the GUI vocabulary to describe the application at a high level.

The browser-facing machinery underneath is deliberately highly leveraged. A Glon view describes enough of a screen for the single-page application, and when something falls outside that vocabulary we can simply drop down to JavaScript rather than continually enlarging the dialect.

That is the same principle I want elsewhere in Glon. Use the high-level dialect for the common case, but retain an escape down to the underlying mechanisms when necessary. We do not have to wrap the entire platform before we can use it.

In the GUI, that means Glon is not trying to implement a complete widget toolkit or reproduce the whole DOM. It describes the useful part of the screen and lets the browser do what browsers already do well.

The result now looks and behaves like a real application: persistent state, routing, events, generated controls, a shopping basket and re-rendering, while the application itself remains Rebol-like.

JavaScript is infrastructure rather than the application language.

The same general principle applies lower down as well. If GQL needs something outside its high-level vocabulary, it can drop down to the underlying prototypes rather than forcing everything through an ever-growing abstraction layer.

So the trick is not to build a full stack at every level. It is to build a small, highly leveraged layer that handles the common case elegantly, while preserving access to the machinery underneath.

And, to me, the nicest bit is View Source.

There are no PHP-style <% ... %> islands, no Cheyenne-style templating, and no giant JSX-style thicket of angle brackets.

You see things like:

home-view: [
    heading [ emit-text "Glon Shop" ]
    tagline [ emit-text "A tiny GLON storefront" ]
    link [ emit-text "View products" ] "products"
]

products-view: [
    heading [ emit-text "Products" ]
    products catalog

    emit-text panel-open
    emit-text search-open
    input "search"
    button [ emit-text "Search" ] "search"
    emit-text search-close

    meta [ emit-text "Search: " emit-text search-term ]
    meta [ emit-text "Products page visits: " emit-int visit-count ]

    emit-text panel-close
    basket

    link [ emit-text "Back home" ] "home"
]

add-product: func [] [
    either str-eq current-value "Tea" [
        tea-count: + tea-count 1
    ][
        either str-eq current-value "Rice" [
            rice-count: + rice-count 1
        ][
            none
        ]
    ]
    render-current
]

The little view vocabulary is itself written in Glon:

wrap: func [open close] [
    func [content] [
        emit-text open
        do content
        emit-text close
    ]
]

heading: wrap h1-open h1-close
subhead: wrap h2-open h2-close
text:    wrap p-open p-close
tagline: wrap tagline-open tagline-close
meta:    wrap meta-open meta-close

So we are not embedding Rebol fragments inside HTML.

The application is the Rebol-family program.

HTML is what it emits.

JavaScript sits underneath as the generic browser host, and we only drop down to it when the browser platform gives us something useful that is not worth reimplementing above.

Live demo:

View Source is probably the best explanation of why I’m pleased with it.

2 Likes

Glon update: traffic, sin, and judgment

The traffic simulator is now live in the browser with four different models: IDM, Newell, OVM/FVDM and NaSch, all running through Glon/WASM.

And today Glon acquired a new datatype:

SIN!

A sin is harmless while inert.
raise it, and it propagates.
judge it, and execution may continue.

This was originally going to be called ERROR!, but where is the fun in that?

Next: seeing how far this tiny language can be pushed beyond traffic simulation.

Live traffic demo:

@hostilefork: in the spirit of reduction, here's a slightly perverse experiment.

Take the Glon ABI — the same way I gave it to @rebolek — and implement it on Ren-C. Don't use our implementation as the model; just satisfy the ABI and see whether the existing Glon examples still run unchanged.

Glon is really a macro assembler, increasingly intended as a small, abstracted and provable language for LMs. Ren-C would be the portable machine underneath it, while retaining useful things it already has — TCP, files and the rest of its cross-platform machinery.

You can continue writing Ren-C directly and doing whatever you like inside the trapdoor. The LM doesn't need to go in there. It programs against the much smaller Glon abstraction on top, whose semantics are deliberately constrained and testable.

There is one important requirement, though: Glon needs a frozen Ren-C core underneath it.

That doesn't mean freezing Ren-C. It means defining the minimum Ren-C machine that implements the Glon ABI, freezing that contract, and letting the rest of Ren-C continue to evolve above and around it.

That also removes much of the bus-factor problem. Once the Glon ABI, tests and the Ren-C core beneath it are frozen, nobody needs to know what was in Brian's head when the machine was written. The behaviour is the specification.

And if you do this, you gain Glon's cooperative multitasking rather than having to design a separate multitasking system for Ren-C.

It needn't mean adding another couple of hundred kilobytes either. As the frozen core is identified, it may become apparent that parts of the existing evaluator are no longer required for this machine. The combined system could ultimately become smaller, not larger.

So the experiment isn't "replace Ren-C with Glon".

It's: freeze a small Ren-C machine, put the provable Glon abstraction on top of it, let the LM program Glon, and see how small the machine underneath can become.

One interesting choice here would be to actually switch to saying "PRINT" instead of "EMIT-TEXT", as I did in my blog dialect Draem. Then if you want to do console logging you could say console-log or similar.

I'm not sure exactly what my schedule for getting to doing this kind of thing is. But with AI help I imagine it could go quickly building on top of the already-working WebAssembly ReplPad framework.

Having AI look at improving Ren-C and the ReplPad is all stuff that could be very interesting. But there's a lot of stuff I am dealing with right now. I'll try to pay attention to what everyone is doing when I can.

Well if you do find the time it will be interesting to compare the implementation on recoil vs renc as the former is also attacking this task. I gather in the process a memory bug was exposed.