I think I’m understanding Mount better now. From the examples:
(ns app
(:require [above :refer [conn]]))
I can refer to conn
in my fn bodies just fine. It’s just that there will be only one value ever bound to above/conn
.This seems to me kind of like Leiningen profiles but without: a) Leiningen profiles (that is, an extra EDN config file on disk) b) the overhead of Leiningen (Mount does a lot less than lein does)
For my use case, if I wanted to have a single db-access
ns talking to two databases I’d have to do that in separate Yurts. Otherwise I could add that db
parameter back to all the fns in my ns and then that ns wouldn’t be using Mount.
back
yes, mount
creates a "managed var" that besides abilities to be "managed" on start / stop behaves like a regular Clojure var. hence
(defn people []
(query db "select * from people"))
would only use one instance of db
, unless of course it is rebound for the scope, which I would not recommend doing, since db
is a resource, and it would make it more complex to followI don't see anything wrong with having this fun taking a db:
(defn people [db]
(query db "select * from people"))
since it makes this function to be "independent" of the db
when you create multiple yurt
s they are just multiple maps of components. here is one:
{:components
{"neo.conf/config" {:www {:port 4242},
:nrepl {:host "0.0.0.0",
:port 7878} ...},
"neo.db/db" {:conn #object[datomic.peer.LocalConnection...]},
"neo.www/neo-app" #object[org.eclipse.jetty.server.Server...],
"neo.app/nrepl" <#C03S1KBA2|clojure>.tools.nrepl.server.Server{:server-socket #object[java.net.ServerSocket... },
:blueprint
{"neo.conf/config" {:order 1},
"neo.db/db" {:order 2},
"neo.www/neo-app" {:order 3},
"neo.app/nrepl" {:order 4}}}
so I am not sure how you would make:
(defn people []
(query db "select * from people"))
work if it does not take db
what yurt
does, it uses mount
to "collect" all the state names and state start/stop functions and then detaches them from vars: i.e. they are no longer attached to any namespace / var.
just curious, why are you after removing db
argument from db functions?
@tolitius I see the benefit of pure functions so I see why passing db
to people
is good. On the other hand I like the brevity that a dynamic var gives me within a namespace.
The traditional, and awful, way, that I often see the db-access
ns implemented is with a dynamic var holding db
. This lets callers use the ns with-bindings
to change the default db
. The downside, of course, is that with-bindings
operates per thread. But the upside is that if I have 20 functions in the ns and they all need the db
, none of the fns have a db arg. Instead they get their db
from the dynamic scope.
It seems that Mount will support this just fine. I can build up db
as state and I can require
it wherever it is needed. When I require it, I put it into the lexical scope, where it (`db`) can be accessed from function bodies.
I understand that this is arguably inferior to pure functions, but it would be valuable for existing namespaces that are written using dynamic vars for config data. It’s also valuable for new namespaces where I do not want to require the caller to provide (global) config state like db
.
If, as you say, there can be only one db
per VM/Pod, then it seems reasonable that some developers might choose to leave that argument off of their argument lists.
cool. I would be curious to see: > When I require it, I put it into the lexical scope, where it (`db`) can be accessed from function bodies. once you done (have some examples) 🙂
Just saying that e.g. start-nyse
here:
https://github.com/tolitius/mount/blob/master/dev/clj/app/www.clj#L32
Could have referenced the conn
from the lexical scope instead of making it part of the arg list.
Doing so would make g. start-nyse
impure. But there are situations where I'd like to try that.
Co-opting the namespace mechanism and IRef
is brilliant!
🙂
it's IDeref
for now
IRef
(to add watchers) is just an idea I had
I see.