Fork me on GitHub
#hoplon
<
2020-03-23
>
flyboarder19:03:00

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

flyboarder19:03:26

generally those things happen during an async process

phronmophobic19:03:15

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

phronmophobic19:03:39

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

flyboarder19:03:12

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

flyboarder19:03:54

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

phronmophobic19:03:00

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

phronmophobic19:03:56

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

phronmophobic19:03:11

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

flyboarder19:03:48

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

flyboarder19:03:59

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

flyboarder19:03:10

micha wrote a similar thing for javafx

phronmophobic19:03:38

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!

flyboarder19:03:10

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

👍 4
phronmophobic19:03:42

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

phronmophobic19:03:42

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

alandipert19:03:26

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

alandipert19:03:49

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

alandipert19:03:06

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

phronmophobic19:03:25

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

phronmophobic19:03:36

which seems like just another cell

alandipert19:03:01

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

hoplon 4
alandipert19:03:42

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

alandipert19:03:17

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

flyboarder19:03:44

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

4
phronmophobic19:03:12

a DOM element?

phronmophobic19:03:36

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?

phronmophobic19:03:08

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

phronmophobic19:03:29

some sort of memoization and caching may be desirable though

alandipert19:03:54

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

phronmophobic19:03:00

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

alandipert19:03:04

e.g. not just that label

flyboarder19:03:20

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

phronmophobic19:03:39

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

flyboarder19:03:59

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

alandipert19:03:16

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

💯 4
alandipert19:03:52

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

phronmophobic19:03:53

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

phronmophobic20:03:01

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

phronmophobic20:03:00

I’ll definitely be on the watch for memory leaks

flyboarder20:03:19

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

micha20:03:29

my javafx thing uses weakrefs

micha20:03:38

so no memory leaks

parrot 4
phronmophobic20:03:50

what’s still hanging onto the old layout?

micha20:03:51

weakrefs don't exist in browsers unfortunately

phronmophobic20:03:04

sorry for all the dumb questions

phronmophobic20:03:24

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

micha20:03:02

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

phronmophobic20:03:02

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

micha20:03:38

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

micha20:03:12

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

micha20:03:27

does that make sense?

phronmophobic20:03:53

but there is no DOM

micha20:03:56

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

micha20:03:04

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

micha20:03:24

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

micha20:03:54

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

phronmophobic20:03:10

well, it’s just a clj map from defrecord

phronmophobic20:03:15

it’s not mutable

micha20:03:28

seems like you want a virtual dom thingy then

micha20:03:00

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

micha20:03:15

without an immutable layer in between

micha20:03:22

because at the end of the day the screen is mutable

micha20:03:41

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

phronmophobic20:03:50

I do have some code for caching draws

micha20:03:02

yeah javafx and the dom handle that

phronmophobic20:03:11

I wrote my own alternative

phronmophobic20:03:29

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

phronmophobic20:03:38

which is the same graphics engine chrome uses

micha20:03:53

it's mutable i assume

micha20:03:05

aka "retained mode"

phronmophobic20:03:16

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

phronmophobic20:03:14

but

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

micha20:03:30

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

micha20:03:43

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

micha20:03:31

defc= returns a var, which is mutable

micha20:03:42

well in clojure it is

phronmophobic20:03:09

sorry, I meant

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

micha20:03:35

i am not familiar with that library

micha20:03:54

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

micha20:03:57

a DOM element

phronmophobic20:03:03

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

phronmophobic20:03:41

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

phronmophobic20:03:06

it seems like it might be a really great fit

micha20:03:38

like a typical hoplon program:

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

micha20:03:23

in this program there are just regular DOM nodes

micha20:03:37

there is no intermediate representation

phronmophobic20:03:38

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

micha20:03:23

swapping cells inside of a formula is iffy

micha20:03:36

normally that would be done as a side effect

phronmophobic20:03:27

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

alandipert20:03:28

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

phronmophobic20:03:13

it initiates a repaint whenever an event occurs.

phronmophobic20:03:34

you can also force a repaint

phronmophobic20:03:00

but the default is whenever an event occurs

micha20:03:25

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

micha20:03:38

because it derefs the cell

micha20:03:37

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

micha20:03:14

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

micha20:03:12

this is with your javelin patch though, right?

micha20:03:24

yeah that's what i was saying above

micha20:03:38

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

micha20:03:47

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

micha20:03:52

which will be actual bugs

phronmophobic20:03:00

ok. I wasn’t sure

phronmophobic20:03:20

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

micha20:03:20

the workaround is just wrap in a cell like above

👍 4
phronmophobic20:03:04

cool. I’ll revert back to the other version

micha20:03:05

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

micha20:03:23

it's hidden basically

micha20:03:48

so you can get glitches, infinite loops, etc

phronmophobic20:03:52

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

phronmophobic20:03:18

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

alandipert20:03:52

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

alandipert20:03:20

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

micha20:03:26

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

phronmophobic20:03:44

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

phronmophobic20:03:59

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

alandipert20:03:22

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

alandipert20:03:38

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

alandipert20:03:06

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

phronmophobic20:03:26

oh, this is probably closer to immediate mode

micha20:03:38

i've had great results with javelin+svg

phronmophobic20:03:40

although, there is some work to save on draw calls

micha20:03:54

svg is the retained mode equivalent of canvas basically

phronmophobic20:03:59

and not do unnecessary repainting

alandipert20:03:01

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

alandipert20:03:17

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

alandipert20:03:44

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

micha20:03:48

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

phronmophobic20:03:17

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

phronmophobic20:03:51

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

alandipert20:03:04

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

phronmophobic20:03:51

ahh. I see. that’s cool

phronmophobic20:03:08

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

micha20:03:43

that's why i was interested in javafx

phronmophobic20:03:08

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

phronmophobic20:03:23

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”

phronmophobic20:03:02

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

alandipert20:03:57

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

alandipert20:03:16

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

alandipert20:03:51

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

micha20:03:27

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

micha20:03:47

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

alandipert20:03:01

javafx is retained mode right?

micha20:03:07

yeah it's like the DOM

micha20:03:13

it even has CSS

micha20:03:22

it's all much more sane and whatnot

micha20:03:33

but essentially the same as the dOM

micha20:03:04

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

micha20:03:19

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

phronmophobic20:03:44

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

micha20:03:46

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

phronmophobic20:03:03

fwiw, membrane also has a WebGL backend

micha20:03:05

yeah that's what hoplon does, kind of

micha20:03:18

hoplon makes the OO stuff into functions

phronmophobic20:03:20

so you can run your same UI in the browser

phronmophobic20:03:00

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

phronmophobic20:03:06

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

micha20:03:14

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

micha20:03:22

but i think it's a huge undertaking

micha20:03:39

keeping things working on all platforms

micha20:03:23

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

phronmophobic20:03:56

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

micha20:03:17

nowadays you need mobile too, no?

alandipert20:03:38

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

phronmophobic20:03:42

skia can also reach mobile

micha20:03:42

and a way to sanely build the app and distribute it

phronmophobic20:03:14

but honestly, I haven’t thought about mobile yet

micha20:03:36

just building a mobile app is a massive amount of work

phronmophobic20:03:47

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

micha20:03:50

and every update breaks your build i'm sure

micha20:03:21

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

phronmophobic20:03:33

xcode can be run from command line

micha20:03:38

none of this build packages via CI/CD

micha20:03:01

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

micha20:03:12

automatically

phronmophobic20:03:35

web app are certainly superior for distribution

micha20:03:54

it's distribution + reach + standardization

phronmophobic20:03:22

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

micha20:03:35

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

phronmophobic20:03:02

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

micha20:03:23

can you run java on mobile?

micha20:03:38

and in the browser?

micha20:03:50

that's where i ended up

micha20:03:08

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

micha20:03:13

but they're all defunct

micha20:03:27

the second they stopped working on it they all broke lol

phronmophobic20:03:32

the ui graphics code and ui frameworks are all platform agnostic

phronmophobic20:03:07

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

micha20:03:04

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

micha20:03:11

because you need to do all the work in JS

phronmophobic20:03:40

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

phronmophobic21:03:01

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

phronmophobic21:03:38

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

micha21:03:43

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

micha21:03:27

i mean because the browser is already installed on every device

phronmophobic21:03:05

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

phronmophobic21:03:14

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

phronmophobic21:03:37

especially for giving a simple UI for less technical users

micha21:03:52

i see, makes sense

phronmophobic21:03:58

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

micha21:03:15

they are all moving to the cloud

phronmophobic21:03:13

I wouldn’t be so sure

micha21:03:26

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

micha21:03:40

things people used to make desktop apps for

micha21:03:20

because you need apis behind the desktop app anyway

micha21:03:30

for authorization and so forth

micha21:03:03

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

phronmophobic21:03:18

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

phronmophobic21:03:40

which may or may not matter depending on your use case

phronmophobic21:03:37

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

dave21:03:27

or run retool on prem 🙂

🙂 4
dave21:03:59

we actually do that at adzerk

dave21:03:17

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

phronmophobic21:03:40

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

phronmophobic21:03:43

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