hoplon 2020-03-23

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

generally those things happen during an async process

this is how i’m using it:

(defc cnt 42)

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

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

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

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

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

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

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

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

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

micha wrote a similar thing for javafx

ok, cool

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!

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

👍 1

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

(html
  (head
    (title "example page"))
  (body
    (h1 "Hello, Hoplon")

    (my-list
      (span "first thing")
      (span "second thing"))

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

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

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

which seems like just another cell

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

1

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

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

➕ 1

a DOM element?

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?

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

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

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

e.g. not just that label

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

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

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.

💯 1

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

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

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

I’ll definitely be on the watch for memory leaks

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

my javafx thing uses weakrefs

so no memory leaks

🦜 1

what’s still hanging onto the old layout?

weakrefs don't exist in browsers unfortunately

sorry for all the dumb questions

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

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

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

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

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

does that make sense?

but there is no DOM

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

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

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

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

well, it’s just a clj map from defrecord

it’s not mutable

seems like you want a virtual dom thingy then

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

without an immutable layer in between

because at the end of the day the screen is mutable

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

I do have some code for caching draws

yeah javafx and the dom handle that

I wrote my own alternative

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

which is the same graphics engine chrome uses

it's mutable i assume

aka "retained mode"

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

but

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

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

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

defc= returns a var, which is mutable

well in clojure it is

sorry, I meant

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

i am not familiar with that library

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

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

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

it seems like it might be a really great fit

like a typical hoplon program:

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

in this program there are just regular DOM nodes

there is no intermediate representation

the equivalent for membrane would be:

(defc clicks 42)

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

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

swapping cells inside of a formula is iffy

normally that would be done as a side effect

(defc clicks 42)

(defc= counter-ui
  (ui/on
   :mouse-down
   (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?

it initiates a repaint whenever an event occurs.

you can also force a repaint

but the default is whenever an event occurs

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

because it derefs the cell

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

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

this is with your javelin patch though, right?

yeah that's what i was saying above

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

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

which will be actual bugs

ok. I wasn’t sure

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

the workaround is just wrap in a cell like above

👍 1

cool. I’ll revert back to the other version

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

it's hidden basically

so you can get glitches, infinite loops, etc

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

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

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

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

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

oh, this is probably closer to immediate mode

i've had great results with javelin+svg

although, there is some work to save on draw calls

svg is the retained mode equivalent of canvas basically

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

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

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

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))))

ahh. I see. that’s cool

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

that's why i was interested in javafx

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

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”

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

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

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?

yeah it's like the DOM

it even has CSS

it's all much more sane and whatnot

but essentially the same as the dOM

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

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

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

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

fwiw, membrane also has a WebGL backend

yeah that's what hoplon does, kind of

hoplon makes the OO stuff into functions

so you can run your same UI in the browser

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

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

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

but i think it's a huge undertaking

keeping things working on all platforms

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

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

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

skia can also reach mobile

and a way to sanely build the app and distribute it

but honestly, I haven’t thought about mobile yet

just building a mobile app is a massive amount of work

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

and every update breaks your build i'm sure

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

xcode can be run from command line

none of this build packages via CI/CD

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

web app are certainly superior for distribution

it's distribution + reach + standardization

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

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

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

can you run java on mobile?

and in the browser?

that's where i ended up

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

but they're all defunct

the second they stopped working on it they all broke lol

the ui graphics code and ui frameworks are all platform agnostic

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

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

because you need to do all the work in JS

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

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

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

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

i mean because the browser is already installed on every device

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

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

especially for giving a simple UI for less technical users

i see, makes sense

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

they are all moving to the cloud

I wouldn’t be so sure

but maybe

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

things people used to make desktop apps for

because you need apis behind the desktop app anyway

for authorization and so forth

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

yes and no

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

which may or may not matter depending on your use case

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

or run retool on prem 🙂

🙂 1

we actually do that at adzerk

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

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

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