Fork me on GitHub
#hoplon
<
2016-08-19
>
onetom01:08:19

@flyboarder: @micha: @tbrooke: @alandipert: @jumblerg: that monday looks good to me too. in HKT it's monday to tuesday midnight for me if i calculate it well. does anyone knows a good app which can answer "12 pm EST on Monday 8/22 in HKT"?

flyboarder01:08:50

@onetom I use google or wolfram alpha for data conversion

onetom01:08:15

it didnt work in google, that's why im asking

onetom01:08:18

i even had to hint wolfram alpha... it thought EST is AEST instead

onetom01:08:41

but thanks for the hint, i totally forgot about wolfram

flyboarder01:08:05

Yeah I wish the API didn't cost so much, I would use it everywhere lol

onetom02:08:16

@flyboarder: what? the pro is 66USD and even the pro premium is just 120USD/year if it's that good, it totally worth it

onetom02:08:02

ah, ok, that's not about the api...

onetom06:08:32

how can i do a reset! within a formula cell?

(cell= (when registration
             (app.routes/change-tab! :success)
             (reset! app.routes/current-qmap {:email email})))

onetom06:08:40

this reads the current value of app.routes/current-qmap which is a hash-map instead of resetting the qmap cell (since it's dereffed by cell=)

onetom06:08:25

i could extract the reset! into its own function just like i did with change-tab!, but that's a bit annoying

onetom06:08:30

(ah, i would need a dosync too around those two mutations to trigger one calculation propagation only...)

onetom06:08:08

what im trying to do is to go to a different view within my app when a response from an RPC call arrives, but also pass the result of that RPC call as URL parameters to my view

onetom06:08:06

it allows me to directly address a view via a URL while developing, so i wouldn't need to trigger the corresponding backend call just to get the desired state

levitanong07:08:56

Hi @thedavidmeister sorry for the late reply. I stopped using it. :p I've gotten it to work though. Is there anything in particular you'd want to know?

thedavidmeister09:08:54

@levitanong oh, just wondering about general advice

thedavidmeister09:08:07

i suppose, why did you drop it and what are you using now?

levitanong09:08:56

I was trying it out and I liked it. However, I needed to be able to zoom and pan an ordinal axis (because I have a ton of categories) and d3 doesn't support that out of the box, and it needs a workaround. Plottable, being something that builds on d3 is less flexible, and I was too lazy to see if I could implement the workaround there. So instead, I used the basic d3.

thedavidmeister09:08:16

i’m literally drawing a line chart, lol

thedavidmeister09:08:23

the plottable ones just looked nice with thedefault styles

thedavidmeister09:08:04

@onetom i end up writing a separate function, i’d be interested if you find a different approach

beatngu1311:08:17

Anyone using Cursive? Though I have my cells in a regular .cljs file, they’re not resolved.

alandipert12:08:11

@onetom: you want to use a watch or the the formula function

micha12:08:08

@onetom you can also use the ~ form in the formula with cell=

micha12:08:16

like this:

micha12:08:18

(cell=
  (when registration
    (app.routes/change-tab! :success)
    (~(partial reset! app.routes/current-qmap) {:email email})))

micha12:08:50

that "hides" the app.routes/current-qroute name from the cell= macro

micha12:08:31

docs describing behavior of ~ and ~@ here: https://github.com/hoplon/javelin#formulas

micha12:08:05

the issue of course was that inside the cell= body expression cells are automatically dereferenced, so you can't operate on the cell itself, only its dereferenced value

micha12:08:38

the ~ form causes the expression it's unquoting to be hoisted out of the formula expression and is evaluated when the cell is constructed, instead of when the cell updates

micha12:08:14

my example above is equivalent to making a function that wraps the reset! call

onetom13:08:53

well, i did understand why it does not work. what i still don't understand whats wrong with:

(cell=
  (when registration
    (app.routes/change-tab! :success)
    (reset! ~app.routes/current-qmap {:email email})))

onetom13:08:07

ah, got it..

micha13:08:33

yeah that evaluates to a cell still

micha13:08:53

so it gets dereferenced when the formula updates

micha13:08:59

(reset! ~(cell app.routes/qmap) {:email email}) should also work

micha13:08:30

then the first deref returns the cell you want to reset

onetom13:08:34

to understand why it works is still as complex as the partial function, but aesthetically it's better

micha13:08:06

so the following: (cell= (+ a b)) is the same as ((formula +) a b)

onetom13:08:20

from runtime perspective which one is more expensive, a new cell or a new partial function?

micha13:08:10

and (cell= (+ (inc a) b)) is the same as ((formula (fn [x y] (+ (inc x) y))) a b)

micha13:08:47

(cell= (+ ~(inc a) b) is the same as ((formula +) (inc a) b)

micha13:08:12

so the formula never sees a in this case

micha13:08:27

because formula is a normal function, not a macro

onetom13:08:37

these are great examples. should we include them into the javelin readme? because what it says about the formula function is rather minimal

micha13:08:37

so (inc a) is evaluated before being passed to it

micha13:08:57

yeah we should also document the formula function i guess

micha13:08:44

there is no performance difference really

micha13:08:57

since the macro simply expands to a formula function

alandipert13:08:15

probably the most we have out there about formula is using it in JS http://adzerk.com/blog/2015/06/splint-functional-first-aid-jquery/

onetom13:08:23

btw, why the path-cell is not part of javelin.core?

micha13:08:29

if you hand-craft your formula function you can maybe prevent some unnecessary hoisting, but i really doubt it will make a difference

micha13:08:32

the "hoisting" is what i mean by pulling references out of the body like (cell= (+ a b)) --> ((formula (fn [x y] (+ x y))) a b)

onetom13:08:38

@alandipert i read that about a year ago. great article. but all i remember from it is it's possible to use the cell concept directly from javascript

micha13:08:44

pulling the a and b out of the formula

alandipert13:08:57

@onetom: right, the thing that makes it possible is formula - since JS can't use cljs macros, only cljs functions

onetom13:08:01

i keep finding myself using path-cell but there is no good place/namespace where i could put it 😕

micha13:08:07

maybe we make a javelin.lens namespace?

micha13:08:18

with various useful types of lenses in there?

onetom13:08:45

@alandipert > you want to use a watch or the the formula function i would, but the add-watch has a too generic api and also there is too little docs about it in javelin, so from team work perspective it's not really good to use

micha13:08:01

add-watch is in clojure.core

micha13:08:06

it's not a javelin thing

alandipert13:08:30

@onetom: also i think my suggestion is bad, since the actions you want to do depend on 2 cells

onetom13:08:31

sure, but the javelin docs shoud point out their relation, no?

micha13:08:43

but also whenever i am doing stuff like that i think about how to refactor things

micha13:08:52

and use a lens instead

onetom13:08:33

you mean lens instead of add-watch?

micha13:08:40

like if you find yourself using reset in a formula, it might mean that there is a better refactoring where app.route/qmap is itself a lens

micha13:08:13

yes, lens instead of reset! in formula or add-watch

micha13:08:24

sometimes it makes sense to refactor, sometimes it doesn't

micha13:08:29

just something to think about

onetom13:08:53

ok, i will consider. thanks.

onetom13:08:45

qmap is a lens in this case, btw and im trying to reset! that

adamw13:08:04

@onetom: that cell='s dependency is email and registration, right?

adamw13:08:30

the 'children'

onetom13:08:31

i guess i should consider diverging lenses; that might be a solution

micha14:08:05

the thing you gain from that would be clear dependency graph

onetom14:08:30

@adamw yes, although email was just (cell= (:user/email registration)) when i wrote this example

adamw14:08:49

@micha: actually, is there an easy way to see parents, children & edge dependencies for a given cell?

micha14:08:23

alan made a graph visualization, we have been planning to add it to javelin for a long time

adamw14:08:58

where parents => cells that depend on this cell, children => this cell's dependencies; edge dependencies => cells that change the dependencies of this cell, e.g. (if <edge dep> <cell dep1> <cell dep 2>)

adamw14:08:45

@micha: would be very helpful to see if things go off-graph.

micha14:08:41

cells have "sources" and "sinks" currently

onetom14:08:50

@adamw there such an interface on cells:

cljs.core/IWithMeta
  (-with-meta  [this meta]  (Cell. meta state rank prev sources sinks thunk watches update))

onetom14:08:48

so you can (.-sources (meta some-cell)) (or something like that)

adamw14:08:48

actually do cells have edge dependencies? In other words in my pathological example above. if edge dep is true and cell dep 2 changes, does my cell get re-evaluated?

micha14:08:59

sources are the cells this cell depends on, sinks are the cells that depend on this one

onetom14:08:21

i don't understand what is an edge dependency

micha14:08:26

i don't understand the edge example

micha14:08:27

@onetom you should be able to just do (.-sources some-cell)

micha14:08:38

those are properties of the js object, not metadata

micha14:08:04

the IWithMeta thing is just implementing that protocol on the Cell type, so you can have metadata on cells

adamw14:08:18

@micha @onetom: take the following example:

(defc edge true)
(defc dep1 1)
(defc dep2 2)

(cell= (if edge dep1 dep2))
so here the value of our formula cell is 1, regardless of what dep2 is. In other words, if I reset! dep2 it should not cause our formula cell to re-evaulate

adamw14:08:39

(err,, edit falsy->truthy)

micha14:08:56

@adamw the sources for that formula are edge, dep1 and dep2

micha14:08:06

if any of those change it will recompute

onetom14:08:37

but any other formula cell depending on your (cell= (if edge dep1 dep2)) cell wont recompute because its value hasn't changed

onetom14:08:19

where would this behaviour cause issues? if dep1 would be an expensive formula cell, its latest value is cached in it and it wont be recomputed anyway.

adamw15:08:38

not if both dep1 and dep2 depend on the same leaves. Let's say dep1 is an approximation formula and dep2 is an expensive computation. With strict evaluation it actually doesn't make a difference, both dep1 and dep2 will get evaluated anyway. So we would need to make dep1 and dep2 non-cells, i.e., functions that get passed all dependencies as arguments. And then it works. But it means we can't abstract our control flow, we need to explicitly define segmentation as a destruction of dependency.

flyboarder16:08:48

@onetom what is the contents of this path-cell ??

flyboarder17:08:34

Seems to be from some kind of routing system, are you using a home grown routing system or another cljs library?

flyboarder17:08:49

ah yea hoplon/ui has it’s own routing, no suggestions there unfortunately

micha18:08:53

@flyboarder the path-cell thing creates a lens

micha18:08:07

it doesn't really have anything to do with routing per se

flyboarder18:08:01

@micha right, I was just thinking about what the routing data in the cell might be, if there was a better way to work with the data instead of path-cell, but if it’s not from a routing lib then the direction I was going doesnt really matter