@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
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
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
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.
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
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 stufflike 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 stuffi am not familiar with that library
but with just hoplon if you do (div "hi there")
you get a mutable thing
a DOM element
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
see https://clojurians.slack.com/archives/C08BDAPRA/p1584911366276900
this is with your javelin patch though, right?
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
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))))
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
ahh. I see. that’s cool
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
automatically
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 🙂
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!
godspeed @smith.adriane