Fork me on GitHub
#hoplon
<
2015-09-17
>
donmullen13:09:05

Pretty impressive flexbox library for reageant — doing some interesting things there - with impressive demo. Something to learn from for hoplon perhaps :http://re-demo.s3-website-ap-southeast-2.amazonaws.com/#/h-box

alandipert13:09:07

that's great! too bad those aren't functions

alandipert13:09:12

they sure are documented like them 😉

xificurC13:09:22

pretty big library

xificurC13:09:00

let's write a macro that rewrites the damn thing into hoplon simple_smile

donmullen14:09:10

I really do think having equivalent out-of-the-box functionality for hoplon would be a huge win as far as interest / uptake of hoplon.

micha14:09:19

jumblerg showed me some interesting flex type stuff he's been doing with hoplon this morning

donmullen14:09:46

Expand on what micha started with boot - but integrated tightly and mostly inline.

donmullen14:09:59

@micha: he needs to open up that code!

micha14:09:26

i think he's going to write it up, i hope so anyway

micha14:09:52

yeah his library uses hoplon as a low level foundation

micha14:09:11

he doesn't use any of the hoplon stuff directly in his applications

micha14:09:29

his library sits on top of hoplon

donmullen14:09:48

he definitely codes bottom-up

micha14:09:01

which is exactly what we intended

micha14:09:23

the existing DOM model isn't good for what we do with it

micha14:09:32

hopefully we can build something better on top of it

micha14:09:45

but without losing the simplicity etc

micha14:09:03

like we don't want to build swing on DOM

donmullen14:09:42

a set of light-weight components built using flexbox would be a great start

micha14:09:30

he actually did something even better, i think

micha14:09:48

he implemented custom attributes that you can use with any element

micha14:09:58

that implement the flex constraint stuff

xificurC14:09:02

seconded. I would gladly learn 50 new functions (that return custom DOM elements) that make sense. Right now it seems like everything is a div in html

micha14:09:08

using a combination of css and js under the hood

micha14:09:46

his library doesn't ship components, other than i think a few primitive ones

micha14:09:00

mostly it's attributes that intelligently maintain constraints and whatnot

micha14:09:15

basically he's reengineered the DOM

xificurC14:09:40

that's what the web needs anyway, no?

xificurC14:09:46

is this closed source or what

micha14:09:25

yeah it's part of his project at the moment

micha14:09:31

not open source

micha14:09:53

he's made a few iterations of the concept now

micha14:09:00

over the past year or two

xificurC14:09:25

I should start writing my app so I get more hands-on experience with hoplon, but got too much work on my hands lately. And I'm really lazy setting things up 😞

xificurC15:09:45

I see wrap-castra-session and wrap-castra in the middleware namespace. I guess those can be used as other ring middleware?

micha15:09:23

the wrap-castra-session is specific to castra

micha15:09:36

i'm using it to simplify passing credentials with CORS

xificurC15:09:50

so something like (-> app-routes wrap-castra app-defaults) makes sense right? app-routes being the defined route(s) and app-defaults coming from ring defaults

micha15:09:22

castra will try to handle any POST request that makes it to it

micha15:09:31

but it doesn't look at routes at all

micha15:09:50

so you might want to put castra inside your routes

micha15:09:05

eg wrap castra middleware with your routes middleware and the other stuff

micha15:09:12

so it gets to castra last

micha15:09:27

giving all your other middleware a chance to handle the request first

xificurC15:09:00

I see, will try to set that up, thanks

xificurC15:09:03

gotta run now

onetom16:09:52

alandipert: micha: as i understood it's possible to provide kids as a cell to a hoplon dom element but it's not recommended. the reason is performance, if i understood it well. we have experienced a massive "memory leak" and huge slowdowns in our app because our menu implementation was something like this:

(div :id "module-segment"
   (cell= [(when (= "#/module-x" route) (module-x)))
           (when (= "#/module-y" route) (module-y)))
            ...]))

onetom16:09:09

as a side-effect - in the chrome js profiler - we've noticed tons of timers being spinning, mostly kicked off by when-dom

onetom16:09:53

under certain situation which we couldn't narrow down, when-dom seemed to never terminate.

onetom16:09:21

i guess it's something which never should happen but it did, so i was thinking maybe it's a good idea to add some guard conditions to when-dom, just to make it fail a bit more gracefully. something like this maybe:

(defn when-dom [this f]
  (if-not (instance? js/Element this)
    (f)
    (timeout
      (let [retry (atom 60)]
        (fn doit []
          (swap! retry dec)
          (if (.contains (.-documentElement js/document) this)
            (f)
            (if (pos? @retry)
              (timeout doit 20)
              (do (.log js/console "This element is never attached to the DOM:" this)))))))))

micha17:09:33

@onetom: yeah the when-dom spins and it should do like how you say there

micha17:09:27

@onetom: the "cell children" thing is only recommended when the contents of the cell are stateless, meaning the only allocation is dom elements

micha17:09:39

and the reason isn't performance, it's memory leaks simple_smile

micha17:09:33

loop-tpl is for when you need to allocate for local state in the elements

micha17:09:53

that will pool them and ensure that memory isn't leaked

onetom17:09:58

so how would u define "stateless". some dom element which attributes or kids doesnt depend on any cells?

onetom17:09:07

the other day u said something like "nested formula cells are not a good idea, because something something"

micha17:09:04

nested formula cells are just a pain to use with the cell= macro, and i haven't yet seen a case where they're needed

micha17:09:30

whenever i think of doing that i always refactor to get something better

micha17:09:40

so far at least

micha17:09:14

if you have nested cells you can use the formula function and not use cell= at all

onetom17:09:18

so i was thinking what exactly does it mean.

(defc stem1 nil)
(defc= formula1 (some-transform stem1))
(defc= formula2 (other-transform formula1))
is okay, but
(defc stem1 nil)
(defc= formula2 (other-transform (cell= (some-transform stem1))))
is not?

micha17:09:28

that gives you more control over how names are interpreted

micha17:09:00

the nested cell= in the second example seems redundant

onetom17:09:24

sure, in this simple example...

onetom17:09:54

but in practice that what happens when we work with hoplon, just there are a few more layers in between

micha17:09:02

generally if the formulas are getting complicated you're probably better off making a function that takes regular data and just calling that from the formula

micha17:09:30

i mostly use cells for the plumbing, not really for computing so much

micha17:09:51

like cells allow you to guide the dataflow

micha17:09:09

but you don't want to do hardcore computing in there, instead you compute in functions that you can call from the formulas

onetom17:09:33

(defelem elem1 [] (div :class (cell= {...}))
(defelem elem2 [] ...)
(defelem container []
  (cell= (if condition (elem1) (elem2)))

onetom17:09:31

and there u have a formula cell (the map for the :class) created/allocated within another formula cell (the conditional kids)

micha17:09:02

i hardly ever use cell children, i use static allocation whenever possible

onetom17:09:56

i got that, but is there anything inherently wrong with this structure, or it's just more prone to memory leaks or it does memory leak for sure?

micha17:09:08

it really sucks that browsers don't have weak references

micha17:09:34

it will memory leak if the things it's creating keep references to live things in them

onetom17:09:36

which u mentioned before but i still have no idea what does it mean 😞

micha17:09:07

weak refs are like pointers, but the things they point to can be garbage collected

micha17:09:29

i.e. they're pointers that don't increment the reference count of the thing they point to

onetom17:09:05

and what happens if u dereference them after the data they r pointing to got GCd?

micha17:09:16

you get undefined

flyboarder17:09:33

@onetome you will get DOM errors that way (I am dealing with this right now)

onetom17:09:37

or the point is that u won't do that because the structure of your program just wont allow that to happen?

micha17:09:07

well like javelin for example needs to keep a graph of all the cells and how they're connected to each other

micha17:09:23

currently this means that the graph needs to be GC as a whole

onetom17:09:31

flyboarder: can u give an example of an error u r talking about?

micha17:09:34

because there are references to all the things in there

micha17:09:07

it would be better if the graph could be GC piecewise, depending on whether your code references cells or not

micha17:09:27

a cell only referenced by the cell graph should be disposed of

onetom17:09:31

micha: but then u would run ur own special cell graph GC to clean up the refs to the disposed cells, no?

micha17:09:49

no, it would just work i think

flyboarder17:09:54

@onetom: sure, yesterday I ran into the issue where my nested cell's wouldnt work as expected because the cell's had already been evaled (maybe dereferenced?) so trying to reset the cell wouldnt work i.e. "Error: cannot change Number 0...." something along those lines it wasnt a cell anymore

micha17:09:21

we'd use strong references from a cell to the cells it depends on

micha17:09:34

and weak references from the cell to the cells that depend on it

onetom17:09:34

flyboarder: thats sounds something different...

flyboarder17:09:49

i was using the same method as your example

onetom17:09:37

okay. what i mean i never saw such an error u just showed, that's why i suspect there was some other reason for that

flyboarder17:09:57

pressing a button would constantly throw the error, I asked micha and he suggested getting rid of the cell=

onetom17:09:04

and i saw quite a lot of errors and they are very memorable... simple_smile

flyboarder17:09:14

haha yeah 😛

flyboarder17:09:26

especially when you are seeing them all day 😞

flyboarder17:09:57

how are your nested cell's being built?

micha17:09:34

nested cells is a strong indication that something can be refactored and made simpler

flyboarder17:09:11

@micha but what about the case as @onetom pointed out? that will happen in most apps at some point no?

micha17:09:48

i don't have nested formula cells in any application i've made with javelin yet

micha17:09:13

every time i thought i needed them i always realized that there was a simpler way to do it

flyboarder17:09:40

brain explode

onetom17:09:48

so i explained this to my colleagues today like this: u can control the attributes of dom elements reactively via cells, but the dom elements themselves should not be added to or removed from the dom reactively. loop-tpl however can "safely" add/remove elements to/from the dom so if u really want some elements to be sometimes present sometimes absent from the dom, then use loop-tpl somehow.

micha17:09:10

right or just show/hide

onetom17:09:35

show/hide? u mean toggle?

micha17:09:39

loop-tpl will cleverly pool any allocated memory and reuse elements from the pool when possible

micha17:09:02

so although loop-tpl removes things from the dom it doesn't try to deallocate them

micha17:09:13

it puts them back in the pool and reuses them later

flyboarder17:09:47

brain more explode

onetom17:09:59

and wouldnt it make sense to have a similar solution for toggling?

micha17:09:15

onetom: yeah you're probably right

onetom17:09:37

when i ask myself "why would it be good to not have the invisible elements in the dom?" im not very sure what would i answer, beside it's a bit confusing / disrupting / annoying to see a bunch of style="display:none"s in the chrome inspector

onetom17:09:03

plus there is no 1-to-1 mapping between what i see rendered and what i see in the dom inspector

micha17:09:04

think about how hoplon would know where to reinsert it

micha17:09:17

like if it removes something from the dom

micha17:09:24

how does it know where to put it back?

onetom17:09:28

im not sure but u solved that somehow with loop-tpl ;D

micha17:09:50

but it's slightly more complicated than just hiding

micha17:09:07

we'd basically make a mini-loop-tpl for toggle

micha17:09:55

we can totally do it

onetom17:09:13

but do we agree on the reason why would such a thing be good? are there any other reasons? do these reasons worth having the added complexity?

onetom17:09:32

i see this more like a social benefit

micha17:09:40

we would have to make a macro probably also

micha17:09:45

or at least a function

onetom17:09:47

to lower the impedance between what ppl expect and what hoplon delivers

micha17:09:53

we couldn't use an attribute

onetom17:09:30

i keep finding myself worrying about what goes into the dom... it's just not a good mental model that "things are there just hidden"

micha17:09:02

yeah, perhaps

onetom17:09:03

not sure if CSS rules which rely on adjacency wouldnt break for example with the current model

onetom17:09:49

imagine u have sections below each other but u dont want extra top margin before the 1st and after the last

onetom17:09:04

what happens however if the 1st section is hidden?

micha17:09:50

this is a good example of when it's safe to use cell children

micha17:09:04

in this case all allocation is handled externally

micha17:09:19

the toggle function doesn't allocate dom elements or wire them up to cells

onetom17:09:34

flyboarder: is there anything left from your brain still? simple_smile

onetom17:09:59

micha: i feel like im starting to understand what are we talking about simple_smile

micha17:09:16

💥 :thumbsup:

micha18:09:58

we want to get to the point where we've carefully designed all the places where we're moving things in and out of the dom

micha18:09:19

because managing memory manually is a huge bummer

micha18:09:13

loop-tpl helps you in that way

micha18:09:32

we could add more like this toggle function and like that

micha18:09:24

well that shouldn't leak

micha18:09:34

because the old spans aren't referenced by anything

micha18:09:03

(div (cell= (if show? [(span :foo some-cell "hi")] [])))

micha18:09:23

that will leak because now it can't be collected until some-cell is

micha18:09:55

is that good or bad 💥 ?

micha18:09:19

this is kind of why we don't want to even deal with this directly

micha18:09:30

it's not easy to reason about

micha18:09:41

this is what i don't like about reactjs really

micha18:09:46

the lifecycle protocols

onetom18:09:48

which i found myself telling to other people too, but then i realized i couldnt explain myself clearly enough what does that mean, so probably they dont understand it either..

micha18:09:11

the IWillMount etc

micha18:09:29

init and cleanup for when things go into and out of the dom

onetom18:09:30

yeah, i know what does it mean on the surface, but then thats it

onetom18:09:01

like detaching event handlers?

micha18:09:23

also breaking references that will cause leaks

micha18:09:41

like if you hold a reference to 2 things in a closure

micha18:09:48

like (fn [x] (+ x a b))

micha18:09:03

this now links the GC of a, b, and the closure

micha18:09:19

if anything holds a reference to that closure then it can't be collected

micha18:09:28

and that means that a and b can't be collected either

micha18:09:35

with hoplon we can eliminate 90% of this kind of thing by just not churning things into and out of the dom

onetom18:09:44

i also wanted to ask u if this when-dom is really necessary and why? is it just the handling of some edge case or it's a regular state during the dom assembly?

micha18:09:12

it might be useless now

micha18:09:20

it's from the beforetimes for sure

onetom18:09:04

i saw there is with-dom using it but with-dom itself was not used anywhere within the hoplon lib at least

micha18:09:29

i think it might be from the first implementation of loop-tpl

onetom18:09:35

(defmacro with-dom
  [elem & body]
  `(when-dom ~elem (fn [] ~@body)))

micha18:09:43

where we actually put a placeholder sentinel element in the dom

onetom18:09:24

micha: oh, yeah, another important thing i wanted to mention. we saw some errors thrown from the test.clj... 1st i was puzzled and thought some test suite got packaged together with hoplon, but then i saw it's a helper namespace which was made to house a test result reporter within the browser. but it defines some cells and those were throwing errors when we were having these memory leaks...

onetom18:09:32

maybe they shouldn't be there by default?

micha18:09:16

yeah we should probably make that separate

micha18:09:41

how was that being compiled though?

micha18:09:52

you didn't :require hoplon.test namespace did you?

onetom18:09:07

and to make it absolutely clear: i was not trying to use it. i was not even aware it's there...

micha18:09:29

it's really weird that it would eevn end up in your project

micha18:09:44

perhaps there is an issue with the cljs compilation

onetom18:09:49

yeah, i definitely haven't required it

onetom18:09:03

i've also upgraded to 1.78.122 as i saw in hoplon/build.boot is it necessary for some reason or just that was the latest cljsc version which u tested?

micha18:09:31

i was experimenting with goog-define and there is a bug with that that was fixed in .122

onetom18:09:02

i see. thx.

onetom18:09:06

(that sounds a bit scary though... such an instrumental piece in the gcl still have bugs after so many year?!?)

micha18:09:01

it could be a bug in boot-cljs, i dunno

flyboarder22:09:14

@onetom: not much left of it 😲

micha22:09:13

i'd use :toggle unless there were some reason not to

flyboarder22:09:29

@micha do you know of any examples or references for castra with a db?

micha22:09:50

i'm using it with SQL server currently

micha22:09:01

have used it with datomic and postgres and mysql in the past

flyboarder22:09:33

id like to use it with mongo

flyboarder22:09:06

but im not sure how im to wire the user auth up with castra

micha22:09:08

i'm going to make a screencast for castra soon

micha22:09:20

there is a clojure mongo client

micha22:09:24

i think it's called "monger"

flyboarder22:09:31

yeah I was looking at that one

micha22:09:33

you'd want to use that probably

micha22:09:04

user auth usually involves storing the user id in the session

micha22:09:38

you can have a precondition (the :rpc/pre key) that checks that and throws an exception if no auth is in the session

micha22:09:01

castra exposes the session as castra.core/*session*

micha22:09:26

it's an atom you can deref to get the contents or swap! / reset! to set the contents

flyboarder22:09:54

so thats how I can persist session data between calls

flyboarder22:09:38

is there a session accessor in hoplon?

flyboarder22:09:58

seems i need to run a local copy of the old site 😛

micha23:09:05

you need to use some ring session middleware

micha23:09:16

there is one that uses cookies which is what i use

micha23:09:33

it stores the session data in an encrypted cookie in the client

micha23:09:46

pretty much any ring session middleware will work with castra

micha23:09:02

castra exposes the session to you via *session*

micha23:09:22

so you can read and write to that atom

micha23:09:32

and the session data will be persisted in the cookie in the client

flyboarder23:09:53

@micha: ok im looking at the castra-chat example https://github.com/hoplon/demos/blob/master/castra-chat/src/castra/demo/core.clj is this still a valid example ?

micha23:09:35

it's a little old

flyboarder23:09:55

ok so then I dont really do much work with the response at all, just drop it at a cell and let the formula's react on it, the real work should be on the backend yes?