The :hoplon: ClojureScript Web Framework - http://hoplon.io/
flyboarder 2020-03-23T19:29:00.279100Z

@smith.adriane you shouldnt be resetting or swapping within a formula

flyboarder 2020-03-23T19:29:26.279500Z

generally those things happen during an async process

phronmophobic 2020-03-23T19:30:15.279900Z

this is how i’m using it:

(defc cnt 42)

(defc= counter-ui
   (ui/label cnt)
   (ui/button "more!"
              (fn []
                (swap! ~cnt inc)))))

phronmophobic 2020-03-23T19:30:39.280300Z

so it’s sort-of async. is there a better approach?

flyboarder 2020-03-23T19:31:12.280900Z

well in that case I also wouldnt use a formula cell to return a ui compenent, thats what the template macros are for

flyboarder 2020-03-23T19:31:54.281800Z

elements should be static and their properties dynamic, with the macros for controling when something is in the DOM or not

phronmophobic 2020-03-23T19:32:00.281900Z

i’m trying to integrate javelin* with my jvm ui library, https://github.com/phronmophobic/membrane

phronmophobic 2020-03-23T19:32:56.282900Z

is there a way to get all the template magic to work for my ui elements?

phronmophobic 2020-03-23T19:33:11.283200Z

it’s not DOM based, but maybe it’s similar enough?

flyboarder 2020-03-23T19:33:48.284Z

it would need to be rewritten to support a non-dom environment

flyboarder 2020-03-23T19:33:59.284300Z

im not sure how people are using the clj javelin for their apps

flyboarder 2020-03-23T19:34:10.284600Z

micha wrote a similar thing for javafx

flyboarder 2020-03-23T19:34:23.284800Z


phronmophobic 2020-03-23T19:34:41.285100Z

ok, cool

phronmophobic 2020-03-23T19:36:38.287Z

seems like a good start. i’ve been looking for a ui framework to integrate and it’s been tough finding a good candidate. javelin seems pretty promising. there tends to a be a lot of documentation for building on top of ui frameworks, but less documentation for building “underneath” ui frameworks (understandably). thanks for your help!

flyboarder 2020-03-23T19:37:10.287400Z

Yeah I think hoplonfx will be more along the lines of what you want

phronmophobic 2020-03-23T19:43:42.289Z

it looks like hoplonfx and hoplon also use swap! in event handlers,

    (title "example page"))
    (h1 "Hello, Hoplon")

      (span "first thing")
      (span "second thing"))

    (p (text "You've clicked ~{clicks} times, so far."))
    (button :click #(swap! clicks inc) "click me")))

phronmophobic 2020-03-23T19:44:42.289900Z

do the templating macros do anything to not include event handler functions as part of the template?


@smith.adriane you could do it differently in your library but generally hoplon elements aren't stored in cells


the reason hoplon has special template things for dom nodes is to prevent memory leakage


one way you could mitigate is using weak refs for cell dependencies, i can't remember if micha did that for hoplonfx

phronmophobic 2020-03-23T19:51:25.293200Z

I was assuming the hoplon elements watch the cells they depend on and update when those cells change

phronmophobic 2020-03-23T19:51:36.293500Z

which seems like just another cell


for attributes that is the case, since attributes changing will never result in a new dom node


but when the number of elements is going to change in response to a cell change, you need a special allocator/de-allocation strategy, at least in browsers. which is what for-tpl/if-tpl etc are


it's an unfortunate complexity, it would be nicer if cells could just be used for everything

flyboarder 2020-03-23T19:53:44.295700Z

In formula cells, a new element is returned every time the formula runs, which can cause memory leaks

phronmophobic 2020-03-23T19:54:12.296100Z

a DOM element?

phronmophobic 2020-03-23T19:55:36.297400Z

in my case, (ui/label (str "the count is " cnt)) is just a defrecord. so creating a new label when cnt shouldn’t be a big deal?

phronmophobic 2020-03-23T19:56:08.298200Z

not sure what would be holding a reference to the old label to keep it from being garbage collected

phronmophobic 2020-03-23T19:56:29.299Z

some sort of memoization and caching may be desirable though


oh, like in your defc=, the expression starting with (horizontal-layout ...) will get re-evaluated when any cell referenced inside changes

phronmophobic 2020-03-23T19:57:00.300500Z

but cells only updating when cells change may do most of the memoization work


e.g. not just that label

flyboarder 2020-03-23T19:57:20.300900Z

cells hold a reference to the cells that depend on them, so they are never garbage collected

phronmophobic 2020-03-23T19:57:39.301600Z

right, but creating a new label shouldn’t be a big deal, right?

flyboarder 2020-03-23T19:57:59.302Z

except you are creating an entirely new horizontal layout like alan said


which may or may not be a big deal, it depends how many times its called and how ppl use your app etc.


but we don't recommend putting elements in cells generally because it easily lead to memory problems

phronmophobic 2020-03-23T19:58:53.304100Z

generally, you’d probably want a new horizontal layout if its subelements change and have different sizes

phronmophobic 2020-03-23T20:00:01.306300Z

my experience so far is that the DOM and browser in general add a lot of unnecessary complexity so I’m unclear whether those issues are still a problem without a DOM

phronmophobic 2020-03-23T20:01:00.307900Z

I’ll definitely be on the watch for memory leaks

flyboarder 2020-03-23T20:01:19.308300Z

without a DOM you still have to destroy the old layout, without weak links between the cells that wont happen, im not sure the JVM version has that since the JS version uses strong links

micha 2020-03-23T20:01:29.308600Z

my javafx thing uses weakrefs

micha 2020-03-23T20:01:38.309Z

so no memory leaks

phronmophobic 2020-03-23T20:01:50.309700Z

what’s still hanging onto the old layout?

micha 2020-03-23T20:01:51.309800Z

weakrefs don't exist in browsers unfortunately

phronmophobic 2020-03-23T20:02:04.310Z

sorry for all the dumb questions

phronmophobic 2020-03-23T20:02:24.310600Z

once the cell calculates a new value, wouldnt the old layout be unreferenced?

micha 2020-03-23T20:03:02.311700Z

in my javafx port the approach was similar to the DOM approach

phronmophobic 2020-03-23T20:03:02.311800Z

in my case, a layout is more-or-less just a clj map from defrecord

micha 2020-03-23T20:03:38.312500Z

the idea is that the DOM or whatever is filling that role is similar to a file, you want to update it in place

micha 2020-03-23T20:04:12.313100Z

so when you add an element to the DOM it stays there and its attributes are updated reactively when necessary

micha 2020-03-23T20:04:27.313400Z

does that make sense?

phronmophobic 2020-03-23T20:04:53.314Z

but there is no DOM

micha 2020-03-23T20:04:56.314100Z

instead of diffing a virtual DOM you diff the data that defines the attributes of elements

micha 2020-03-23T20:05:04.314400Z

there is always a DOM if you have a UI, no?

micha 2020-03-23T20:05:24.315Z

even if you're directly manipulating memory in a graphics card

micha 2020-03-23T20:05:54.315700Z

there is a bunch of memory representing what's being displayed on the screen

phronmophobic 2020-03-23T20:06:10.316200Z

well, it’s just a clj map from defrecord

phronmophobic 2020-03-23T20:06:15.316500Z

it’s not mutable

micha 2020-03-23T20:06:28.316900Z

seems like you want a virtual dom thingy then

micha 2020-03-23T20:07:00.317900Z

the idea of hoplon is to update the memory that represents what's on the screen in place, as a side effect

micha 2020-03-23T20:07:15.318200Z

without an immutable layer in between

micha 2020-03-23T20:07:22.318500Z

because at the end of the day the screen is mutable

micha 2020-03-23T20:07:41.319100Z

when you update a div your monitor doesn't poof out of existence and get replaced

phronmophobic 2020-03-23T20:07:50.319400Z

I do have some code for caching draws

micha 2020-03-23T20:08:02.319700Z

yeah javafx and the dom handle that

phronmophobic 2020-03-23T20:08:11.320Z

I wrote my own alternative

phronmophobic 2020-03-23T20:08:29.320300Z

I use skia under the hood, https://skia.org/

phronmophobic 2020-03-23T20:08:38.320600Z

which is the same graphics engine chrome uses

micha 2020-03-23T20:08:53.320800Z

it's mutable i assume

micha 2020-03-23T20:09:05.321Z

aka "retained mode"

phronmophobic 2020-03-23T20:10:16.321600Z

yes, there is a buffer at the bottom that is drawn to

phronmophobic 2020-03-23T20:11:14.322100Z


(defc= counter-ui
   (ui/label cnt)
   (ui/button "more!"
              (fn []
                (swap! ~cnt inc)))))
doesn’t create mutable stuff

micha 2020-03-23T20:11:30.322500Z

like in hoplon in the browser there is no immutable representation of the DOM

micha 2020-03-23T20:11:43.322800Z

javelin cells update DOM elements as a side effect, in place

micha 2020-03-23T20:12:31.323200Z

defc= returns a var, which is mutable

micha 2020-03-23T20:12:42.323400Z

well in clojure it is

phronmophobic 2020-03-23T20:13:09.323900Z

sorry, I meant

 (ui/label cnt)
 (ui/button "more!"
            (fn []
              (swap! ~cnt inc))))
doesn’t create mutable stuff

micha 2020-03-23T20:13:35.324600Z

i am not familiar with that library

micha 2020-03-23T20:13:54.325300Z

but with just hoplon if you do (div "hi there") you get a mutable thing

micha 2020-03-23T20:13:57.325600Z

a DOM element

phronmophobic 2020-03-23T20:14:03.325800Z

it’s fairly new (to others, I’ve been using it for a year). I just “released” it last week

phronmophobic 2020-03-23T20:14:41.326800Z

i’m currently in the process of trying to integrate popular ui frameworks and javelin looks really cool

phronmophobic 2020-03-23T20:15:06.327200Z

it seems like it might be a really great fit

micha 2020-03-23T20:15:38.327900Z

like a typical hoplon program:

(defc clicks 0)
    :click #(swap! clicks inc)
    (cell= (str "you clicked " clicks " times!"))))

micha 2020-03-23T20:16:23.328500Z

in this program there are just regular DOM nodes

micha 2020-03-23T20:16:37.329Z

there is no intermediate representation

phronmophobic 2020-03-23T20:16:38.329100Z

the equivalent for membrane would be:

(defc clicks 42)

(defc= counter-ui
   (ui/label (str you clicked " clicks "times!")
   (ui/button "more!"
              (fn []
                (swap! ~clicks inc)))))

(ui/run #(deref counter-ui))

micha 2020-03-23T20:18:23.329700Z

swapping cells inside of a formula is iffy

micha 2020-03-23T20:18:36.330Z

normally that would be done as a side effect

phronmophobic 2020-03-23T20:19:27.331100Z

(defc clicks 42)

(defc= counter-ui
   (fn [_]
     (swap! ~clicks inc))
   (ui/label (str "you clicked " clicks " times!"))))

(ui/run #(deref counter-ui))


@smith.adriane does ui/run invoke the function on some interval?

phronmophobic 2020-03-23T20:20:13.332Z

it initiates a repaint whenever an event occurs.

phronmophobic 2020-03-23T20:20:34.332400Z

you can also force a repaint

phronmophobic 2020-03-23T20:21:00.333200Z

but the default is whenever an event occurs

micha 2020-03-23T20:21:25.333900Z

you're not seeing the swap! work properly in there, right?

micha 2020-03-23T20:21:38.334300Z

because it derefs the cell

micha 2020-03-23T20:22:37.335Z

the way to do it would be (swap! ~(cell clicks) inc)

micha 2020-03-23T20:23:14.335600Z

it looks weird i'm sure, but that's because it wasn't really intended to swap cells inside formulas

phronmophobic 2020-03-23T20:23:38.335900Z

phronmophobic 2020-03-23T20:24:09.336500Z

see https://clojurians.slack.com/archives/C08BDAPRA/p1584911366276900

micha 2020-03-23T20:24:12.336900Z

this is with your javelin patch though, right?

phronmophobic 2020-03-23T20:24:16.337100Z


micha 2020-03-23T20:24:24.337600Z

yeah that's what i was saying above

micha 2020-03-23T20:24:38.337900Z

that's a known issue but it's not a bug

micha 2020-03-23T20:24:47.338200Z

if you "fix" it you'll have other issues

micha 2020-03-23T20:24:52.338500Z

which will be actual bugs

phronmophobic 2020-03-23T20:25:00.338800Z

ok. I wasn’t sure

phronmophobic 2020-03-23T20:25:20.339400Z

I wasn’t sure what the semantics were supposed to be.

micha 2020-03-23T20:25:20.339500Z

the workaround is just wrap in a cell like above

phronmophobic 2020-03-23T20:26:04.340900Z

cool. I’ll revert back to the other version

micha 2020-03-23T20:26:05.341Z

note that that cell won't participate in the dependency graph

micha 2020-03-23T20:26:23.341300Z

it's hidden basically

micha 2020-03-23T20:26:48.341900Z

so you can get glitches, infinite loops, etc

phronmophobic 2020-03-23T20:26:52.342100Z

the way I wrote the patch doesn’t add it to the dependency graph

phronmophobic 2020-03-23T20:27:18.342600Z

but I’m still new to javelin, so there’s probably other issues I’m not considering


one big thing i see is that your underlying graphics API is not the one javelin was designed to interoperate with


javelin evolved in the browser where there is not global repaint operation, but many small UI objects that individually trigger repainting on themselves. by adding children or changing attributes

micha 2020-03-23T20:28:26.344300Z

the intended use is to do secondary swapping from a watch added to the formula, rather than from inside the formula expression

phronmophobic 2020-03-23T20:29:44.345500Z

that’s part of the issue i’m running into. none of the popular clj(s) ui frameworks are designed with the graphics API I’m using

phronmophobic 2020-03-23T20:30:59.347300Z

it might be that my graphics API is goofy, but I’ve been having fun making UIs in clj on the jvm without divs, spans, DOMS, and javascript nonsense


its not goofy, it seems pretty standard. there are basically two categories, immediate-mode and retained-mode


an immediate-mode graphics interface is one where every event triggers a full repaint


retained-mode is when the granularity of repaint events is encapsulated into some set of lower-level graphics objects that manage their own display

phronmophobic 2020-03-23T20:32:26.349400Z

oh, this is probably closer to immediate mode

micha 2020-03-23T20:32:38.349900Z

i've had great results with javelin+svg

phronmophobic 2020-03-23T20:32:40.350100Z

although, there is some work to save on draw calls

micha 2020-03-23T20:32:54.350700Z

svg is the retained mode equivalent of canvas basically

phronmophobic 2020-03-23T20:32:59.351Z

and not do unnecessary repainting


one thing that might be useful is react implements immediate mode on top of retained mode


so to the extent that your graphics are immediate mode, approaches people are using to do react from cljs might be good


a lot of those apis look kinda like what you have. reagent in particular. but instead of bottoming out at React stuff, your version could bottom out at your own graphics objects

micha 2020-03-23T20:33:48.352600Z

if you want to update entities that are already drawn you're in retained mode already

phronmophobic 2020-03-23T20:34:17.353400Z

right now, my biggest issues are performance issues. I’ve been pleasantly surprised at how snappy things feel without too much effort

phronmophobic 2020-03-23T20:34:51.354700Z

my biggest issues are around having ui frameworks that people can use to start making desktop uis with frameworks people are familiar with


maybe the shortest example of the difference is like (let [count (cell 0)] (button :click #(swap! count inc) (cell= (str count))))

phronmophobic 2020-03-23T20:35:08.355300Z

basically, noone wants to make a UI and have to build their own text box from scratch

micha 2020-03-23T20:35:43.355500Z

that's why i was interested in javafx

phronmophobic 2020-03-23T20:36:51.355800Z

ahh. I see. that’s cool

phronmophobic 2020-03-23T20:38:08.357100Z

I’m ok with doing the work to build the builtin textbox, but the issue is figuring out the best design for that in the target ui framework

phronmophobic 2020-03-23T20:39:23.358200Z

since most frameworks target the browser and have stuff like focus, text handling, etc. baked in. there’s not much guidance for how one might build those components “from scratch”

phronmophobic 2020-03-23T20:40:02.359100Z

I view dealing with the browser’s forceful control over focus, text cursors, etc as a necessary evil rather than a desirable design


i havent seen any high level graphics APIs that are dramatically different from what the browser does, personally


retained mode APIs that is. but the way the browser can't trust the javascript is one annoying aspect for sure


i haven't worked with it but this is my sense for what javafx is, a retained-mode interface but without browser legacy and sandboxing

micha 2020-03-23T20:42:27.361100Z

was interested in javafx because it runs in a non-crippled computing platform

micha 2020-03-23T20:42:47.361600Z

but at the end of the day i think i would only use it for a really restricted set of programs


javafx is retained mode right?

micha 2020-03-23T20:43:07.362200Z

yeah it's like the DOM

micha 2020-03-23T20:43:13.362400Z

it even has CSS

micha 2020-03-23T20:43:22.362700Z

it's all much more sane and whatnot

micha 2020-03-23T20:43:33.362900Z

but essentially the same as the dOM

micha 2020-03-23T20:44:04.363700Z

but the downside is you can really only make desktop applications with it

micha 2020-03-23T20:44:19.364400Z

so like 99.99999% of the time i'd have to make a webapp anyway

phronmophobic 2020-03-23T20:44:44.365100Z

my goal was to have a function interface all the way down and have an alternative to the OO DOM-like options

micha 2020-03-23T20:44:46.365200Z

far as i can tell the only feasible way to make a cross platform application is in the browser

phronmophobic 2020-03-23T20:45:03.365600Z

fwiw, membrane also has a WebGL backend

micha 2020-03-23T20:45:05.365700Z

yeah that's what hoplon does, kind of

micha 2020-03-23T20:45:18.366300Z

hoplon makes the OO stuff into functions

phronmophobic 2020-03-23T20:45:20.366400Z

so you can run your same UI in the browser

phronmophobic 2020-03-23T20:47:00.368Z

I’ll probably add other backends in the future that “draw” to the dom. I’d also like to have an ncurses backend at some point since that sounds fun

phronmophobic 2020-03-23T20:48:06.369500Z

basically, if you can draw lines, text, and images, then you should be able to swap out the graphics implementation and continue using the same UI framework and code

micha 2020-03-23T20:48:14.369600Z

if somebody (hint, hint) made a true cross-platform UI kit i'd use it

micha 2020-03-23T20:48:22.369900Z

but i think it's a huge undertaking

micha 2020-03-23T20:48:39.370300Z

keeping things working on all platforms

micha 2020-03-23T20:49:23.371500Z

but google does that with chrome out of the box, the thing runs anywhere

phronmophobic 2020-03-23T20:49:56.371900Z

that’s what i’m working towards. skia + glfw does a pretty good job at reaching desktop OSs and having compatibility

micha 2020-03-23T20:50:17.372700Z

nowadays you need mobile too, no?


@micha is a javafx browser shim an option? or is it too many things to emulate in the browser

phronmophobic 2020-03-23T20:50:42.373900Z

skia can also reach mobile

micha 2020-03-23T20:50:42.374Z

and a way to sanely build the app and distribute it

phronmophobic 2020-03-23T20:51:14.374800Z

but honestly, I haven’t thought about mobile yet

micha 2020-03-23T20:51:36.375700Z

just building a mobile app is a massive amount of work

phronmophobic 2020-03-23T20:51:47.376200Z

I want a design that could support it in the future, but I’m focusing on making desktop usable at the moment

micha 2020-03-23T20:51:50.376300Z

and every update breaks your build i'm sure

micha 2020-03-23T20:52:21.376800Z

you need to manually click buttons in apple's UI on a mac on your desk

phronmophobic 2020-03-23T20:52:33.377200Z

xcode can be run from command line

micha 2020-03-23T20:52:38.377400Z

none of this build packages via CI/CD

micha 2020-03-23T20:53:01.377900Z

witha web app i can just put a html file on s3 and we're done

micha 2020-03-23T20:53:12.378200Z


phronmophobic 2020-03-23T20:53:35.378600Z

web app are certainly superior for distribution

micha 2020-03-23T20:53:54.379200Z

it's distribution + reach + standardization

phronmophobic 2020-03-23T20:54:22.379800Z

but there is a non trivial amount incidental complexity introduced by the browser

micha 2020-03-23T20:54:35.380400Z

apple and ms are always going to break you on purpose if you do manage to defeat their countermeasures

phronmophobic 2020-03-23T20:55:02.380800Z

as long as you can get java to run, then membrane will work

micha 2020-03-23T20:55:23.381Z

can you run java on mobile?

micha 2020-03-23T20:55:38.381200Z

and in the browser?

micha 2020-03-23T20:55:50.381400Z

that's where i ended up

micha 2020-03-23T20:56:08.381900Z

there were some projects to make javafx cross-platform, they were almost there

micha 2020-03-23T20:56:13.382100Z

but they're all defunct

micha 2020-03-23T20:56:27.382600Z

the second they stopped working on it they all broke lol

phronmophobic 2020-03-23T20:56:32.382800Z

the ui graphics code and ui frameworks are all platform agnostic

phronmophobic 2020-03-23T20:57:07.383400Z

so you just swap out the graphics implementation for running the same UI in the browser

micha 2020-03-23T20:58:04.384300Z

seems like you'd have a lot of perf issues doing a whole UI in canvas

micha 2020-03-23T20:58:11.384500Z

because you need to do all the work in JS

phronmophobic 2020-03-23T20:58:40.384800Z

for mobile, I’m hoping graalvm stuff will save the day and allow you to just compile your UI to an executable

phronmophobic 2020-03-23T21:00:01.385600Z

performance hasn’t been an issue, but canvas doesn’t seem like the optimal solution

phronmophobic 2020-03-23T21:00:38.386700Z

I think the best route is to have it spit out a virtual dom and use a js vdom library

micha 2020-03-23T21:00:43.387Z

if you can make a better browser DOM why not just use that? then there is no need for a native implementation right?

micha 2020-03-23T21:01:27.387400Z

i mean because the browser is already installed on every device

phronmophobic 2020-03-23T21:02:05.387900Z

I think it’s reasonable to want to make UIs with clj on the jvm

phronmophobic 2020-03-23T21:02:14.388200Z

I’ve been using it for internal tooling at my company and it’s great

phronmophobic 2020-03-23T21:02:37.388800Z

especially for giving a simple UI for less technical users

micha 2020-03-23T21:02:52.389Z

i see, makes sense

phronmophobic 2020-03-23T21:03:58.389800Z

you may also notice that most productivity tools (photoshop, excel), especially for programmers, aren’t web apps (git, emacs, etc).

micha 2020-03-23T21:04:15.390300Z

they are all moving to the cloud

phronmophobic 2020-03-23T21:05:13.391Z

I wouldn’t be so sure

phronmophobic 2020-03-23T21:05:17.391400Z

but maybe

micha 2020-03-23T21:05:26.391600Z

there are things like retool for making small helper apps with GUIs

micha 2020-03-23T21:05:40.391900Z

things people used to make desktop apps for

micha 2020-03-23T21:06:20.392500Z

because you need apis behind the desktop app anyway

micha 2020-03-23T21:06:30.392700Z

for authorization and so forth

micha 2020-03-23T21:07:03.393200Z

so once you have a desktop app that is just a facade over APIs you have the equivalent of a webapp

phronmophobic 2020-03-23T21:07:17.393400Z

yes and no

phronmophobic 2020-03-23T21:08:18.394500Z

web apps still stink at working with the file system, they tend to add a bunch of networking complexity, have terrible offline support and they also don’t do a great job of utilizing the underlying hardware

phronmophobic 2020-03-23T21:08:40.394900Z

which may or may not matter depending on your use case

phronmophobic 2020-03-23T21:09:37.395600Z

like if you want to retool to work with your company’s database, you either need to setup some API that retool can work with or give retool’s servers access to your database

dave 2020-03-23T21:12:27.396300Z

or run retool on prem 🙂

dave 2020-03-23T21:12:59.396800Z

we actually do that at adzerk

dave 2020-03-23T21:13:17.397300Z

so far it seems like not many other retool customers do it, based on the support experience 😄

phronmophobic 2020-03-23T21:13:40.397700Z

well*, I just want a platform agnostic UI framework that makes sense to me

phronmophobic 2020-03-23T21:15:43.398400Z

thanks for all the help. I’m gonna keep working at integrating javelin and see how* it goes!


godspeed @smith.adriane