This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-01
Channels
- # aleph (1)
- # architecture (7)
- # aws (1)
- # beginners (52)
- # boot (3)
- # cider (27)
- # cljs-dev (9)
- # cljsrn (16)
- # clojure (82)
- # clojure-dev (75)
- # clojure-italy (14)
- # clojure-nl (11)
- # clojure-spec (10)
- # clojure-uk (31)
- # clojurescript (49)
- # core-async (13)
- # datascript (11)
- # datomic (15)
- # duct (11)
- # emacs (8)
- # fulcro (46)
- # heroku (2)
- # jobs-discuss (27)
- # jobs_rus (1)
- # juxt (25)
- # keechma (1)
- # off-topic (59)
- # om (2)
- # pedestal (4)
- # portkey (113)
- # portland-or (1)
- # re-frame (14)
- # reagent (11)
- # shadow-cljs (278)
- # vim (2)
- # yada (2)
I’m reading the docs for Luminus, and I don’t understand how you’re supposed to keep your application manageable as it grows. It doesn’t seem like there’s a clear place for “business logic”.
@bolivier I have the same question, I think you’re supposed to just create a few namespaces and put some functions there. Then call those functions from the various web handlers.
You might use something Component or Integrant if you have some state (e.g. database connections/setup) — I’m not sure what Luminous uses by default.
Does anybody know what the difference between recur and trampoline is? Kinda confused right now 😞
@denisgrebennicov I actually think if you do (source trampoline)
you might come away with a clear "no-mysteries" understanding of it, since it is build right on top of recur
.
there’s a whole chapter with more detail in Programming Clojure if you want lots more words
My mental model is that it is kind of like a recur
but that looks at the return value to see if it is a function and should continue going...
@mfikes thanks 😅. Still not used to look up to the source code implementation for better understanding 😄
Also, if you haven't seen it, this can aid in understanding: https://clojuredocs.org/clojure.core/trampoline
I guess, when I was reading the description I was confused, because of that mutual recursive part and other than that, it seemed like it was the same as what recur does, namely, calling the function while reusing the stack
You can also use trampoline
to get around (non-mutually-recursive) cases where recur
can't be used. For example, you can't recur
across a try
, but if you really need to, you can fashion a solution using trampoline
.
@denisgrebennicov recur literally reuses the stack, trampoline extends the stack to a new function but only after returning from the previous. It's reuse vs. avoid growing too far.
recur is a goto, trampoline a new function call
The other way to look at recur vs trampoline is that chances are excellent that you mean recur. 😉
I was just reading this blog post: https://deque.blog/2017/06/01/clojure-high-performance-fibonacci/ and they guy was comparing fibonacci implementation recur vs trampoline
almost any numeric benchmark on Clojure is dominated by how well you avoid boxing
as boxed math is ~100x slower than primitive math
what is a good practice to handle database connection functions
I’m doing my execute using a global
invisible connection
I could obviously (defn execute [conn query params])
but I can’t see why should I do that
(def conn (nr/connect " "))
(defn execute [query params]
(-> (cy/tquery conn query params) walk/keywordize-keys))
what best practice in this case, should I pass the connection to be more functional
and my function be more pure
and functional
pass the connection
well, that depends a bit on the semantics
defonce is a pain for interactive development so I try to minimize that too
(all rules are made to be broken eventually, but I think this is a good thing to strive for)
I’ve only ever regretted def’ing state. create it during initialization and pass it around. don’t enshrine it in a var.
when you say @alexmiller create it during initialization
you meant in the begining of the process , boot process ?
in the path of starting your application, cause the state to be created, then inject, close over, pass to those who need it (which of those will depend on what you’re doing)
@alexmiller would you recommend def'ing your state initially, to play with it in the repl? And then rework your functions to be more of a pipeline as you massage your functions into a compilable program?
oh sure, you will likely need some way to def state for edevelopment
but that’s dev stuff
Clojure is most glorious when arranged as pipelines of functions handling data
not all work looks like that though :)
I find when I first approach a problem, I start with all state "exploded" into its parts, sitting in vars
I wonder how closed over state would look in case of failures - ie some database goes down momentarily, connection is closed and you need to reconnect and update all dependencies...
@orestis you can always pass a map back from functions with new state, and function results
I've sometimes found it useful to have a record with a reconnect method, and a shared internal state - but these things are less elegant than I'd like. I think the right solution is to make something like a jdbc connection pool object API, and let it manage its own open connection(s) in its own isolated scope
so what you pass into the code at startup carries not just a currently working connection, but the config that knows how to reconnect, and behavior that manages that
trying to make an implicitly stateful thing act like an immutable thing can make things more complex rather than less if you do it clumsily
Right @noisesmith so instead of passing a connection around you pass a connection manager or something similar. I keep thinking about the Erlang way where you use named processes to hide the details. It’s still global state but it’s hidden away and the calling code is by even aware that there is any state, as at the call site it looks like any plain function. Of course, that’s what we are trying to avoid all along?
right, in clojure you can do that with a closure that exposes a safe api, and handles any trickiness internally
though that should be reserved for things that are intrinsically mutable / stateful