Fork me on GitHub
#mount
<
2016-01-24
>
bbss02:01:05

@tolitius it is expensive in the sense that it hits an api with a limit, the limit might not be a problem but I live in China, which means I don't have the best connectivity when I travel so I like to be able to keep state unreloaded as with an atom in defonce. Actually travel or not, internet to outside the Chinese firewall is unstable. Even the (albeit small unimportant) Google office in Shanghai didn't have decent internet, hahah.

bbss02:01:39

I do change the data in the process, so it is kinda ephemeral. I do save it to be application state though.

tolitius02:01:30

@bbss: wow that's quite a story simple_smile

bbss02:01:32

Heheh, yes, living here is great except for the smog and bad internet.

tolitius02:01:40

looks like there are two things: * this state is mutable * the restart / reload is "expensive" I don't have a good answer.. need to think about it.. looks like the usage implies some kind of start-with path, where you call the real API cache/persist data and then do start-with {#'your/state this-cache}. when you want to refresh that data from API, you would just call start... just thinking out loud without knowing the actual context simple_smile

tolitius02:01:43

also mount should not "restart" a state if you recompile namespace(s) not associated with it

tolitius02:01:53

did not add docs for it yet, but start-with now takes values as substitutes. start-with-states takes states as substitutes.

bbss02:01:35

Wow, quick turnaround. I can separate the state to a different namespace then didn't try that one yet.

bbss02:01:22

That was what I was slightly confused about, I don't need to call start anywhere in this project and defstates will still work.

tolitius03:01:51

@bbss: yes, in cljs, you are probably running in cljc mode? which would mean that states will be lazily started when they are dereferenced: i.e. @my-state

bbss03:01:34

ah, that explains the "has no deref" errors I didn't understand!

tolitius03:01:44

they will also be all started by (mount/start), but this is an interesting property of cljc mode, where the system can be just lazily started

tolitius03:01:55

I might need to make it stand out a little more.. since it does not seem to be easy to find from the docs table of context

bbss03:01:50

ah yes I had read it but still very new to all of it so not sure I understood all.

tolitius03:01:02

*"table of contents"

tolitius03:01:18

ah.. not a problem at all, I can explain

tolitius03:01:16

so the whole idea is, in cljs :advanced optimization wipes out all the namespaces, and renames all the vars, so we can no longer depend on a var being there to change it's value on start/stop

tolitius03:01:31

hence mount has a cljc mode

tolitius03:01:44

(mount/in-cljc-mode)

tolitius03:01:57

that would be called anywhere before a call to (mount/start), usually at the entry point of an app: in the -main, web handler, etc.

tolitius03:01:16

in this mode states are like simple version of an atom

tolitius03:01:54

they don't have all the atom API (i.e. swap / reset!, etc..), but they have a @ (i.e. deref)

tolitius03:01:10

so in order to use the state you would just deref it

bbss03:01:12

right, that's why the double @@ on an atom

tolitius03:01:21

(ns app.websockets
  (:require [app.conf :refer [config]]
            [app.audit-log :refer [audit log]])
  (:require-macros [mount.core :refer [defstate]]))

;; ...

(defstate system-a :start (connect (get-in @config [:system-a :uri]))
                   :stop (disconnect system-a))

tolitius03:01:48

if you deref it without calling (mount/start) it would still work

bbss03:01:56

I see. What would the downside of not calling start be?

tolitius03:01:13

the system would be started lazily, which means you might expect certain things to start on, say, page load, but they would not be, because nobody needed them yet

tolitius03:01:55

e.g. something needs to be loaded, but unless it is referenced anywhere or (mount/start) was called it would not be (loaded)

bbss03:01:37

so biggest problem would be that it takes a little longer load

tolitius03:01:23

that would depend on the use case (app), but I would not say longer, I would say.. it could start certain states at different time

tolitius03:01:01

if you need everything to start, and be very deterministic, you can call (mount/start)

bbss03:01:24

Thanks for the explanations!

bbss03:01:36

I like using mount so far.

bbss03:01:24

Hadn't looked at (or had the need to) component yet and found the recent discussions around mount vs component very interesting. Mount seemed like the more light-weight solution.

tolitius03:01:27

sure, thanks for you feedback, keep it coming simple_smile I am sure we can improve, especially on the cljs side, so I would be very interested to know what works and what does not / could work better

bbss03:01:08

I am experimenting a bit core.async, I needed a way to switch the way a put was handled for testing purposes and mount seemed good for that with it's start-with.

bbss03:01:12

One optimization I think would be nice is to not reload the whole namespace but just the parts that changed. If I am not mistaken that is what figwheel does.

tolitius03:01:46

mount does not reload namespaces simple_smile

tolitius03:01:06

just restarts states that belong to a namespace that was reloaded

bbss03:01:06

I mean restart all the defstates in a namespace that was editted

bbss03:01:31

it's just a nice-to-have I guess, if I don't want a state to be reloaded I can change its namespace.

tolitius03:01:42

ah.. yea, that's a thought. the problem is stale references. for example you have a conn state that holds a connection to a db, when a namespace is recompiled, a new conn reference is created

tolitius03:01:07

that is what I alluded to a little earlier: > it might make sense to make this behavior configurable: https://github.com/tolitius/mount#recompiling-namespaces-with-running-states >I feel like, in cljs, it could address both issues above, especially during full page reloads / sending large recompiled increments (by figwheel)

tolitius03:01:20

so you could potentially say something like

(defstate ^:dont-reload db :start (connect) :stop (disconnect))

tolitius03:01:37

something like that... this is a rough thought simple_smile

tolitius03:01:57

since I don't think it is nice to cary these ^:dont-reload around

bbss03:01:01

or (defstateonce) or does that have different semantics

tolitius03:01:23

well defstate already creates defonce

tolitius03:01:57

mount has logic to cleanup and potentially restart dirty states

tolitius03:01:21

which could be turned off for certain states or for all states..

tolitius03:01:59

might be good to have regardless.. i.e. (mount/don't-reload-on-recompile), but a better name

bbss03:01:59

I see. Something that still got me stuck sometimes with figwheel and cursive is not understanding how to manage creation of go-blocks. If I were to take from a channel with a go block and change the go block and re-evaluate the old go block would also still grab off the channel until I reload the browser.

bbss03:01:20

I haven't tried that yet with mount but maybe that clean-up logic will take care of that too?

tolitius03:01:13

yep, it will, if you provide that logic simple_smile

tolitius03:01:28

i.e. some kind of a poison pill on :stop

bbss03:01:38

not sure how to remove a go block though

tolitius03:01:29

i.e. using a some kind of stop channel to not recur anymore

bbss03:01:27

Thanks. That could help me out.

tolitius03:01:54

sure, let me know how it goes simple_smile

bbss03:01:19

I will, working on different stuff now but I will