This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # beginners (5)
- # cider (4)
- # clojure (60)
- # clojure-austin (1)
- # clojure-berlin (1)
- # clojure-dev (6)
- # clojure-italy (5)
- # clojure-spec (2)
- # clojure-uk (2)
- # clojurescript (13)
- # community-development (17)
- # cursive (5)
- # datomic (11)
- # fulcro (9)
- # hoplon (5)
- # jobs-rus (2)
- # om (1)
- # parinfer (1)
- # protorepl (15)
- # re-frame (10)
- # reagent (12)
- # sql (5)
- # unrepl (3)
I'm assuming you want to take an array of bytes (`[B` in Java-speak) and display it as a Hex value @bradford ?
Hi! Question: is it considered “good practice” to use protocols with a 1-1 correspondence with records. By that I mean the following: I am familiar with protocols as a way to abstract behaviour that various data structures may implement. e.g. Seq, etc. However, I have been tempted to use protocols as a way to define “class-like” things which have state + methods
For example, I have been tempted to define a
DatabaseBoundary protocol together with a record which holds a database connection. The protocol would have a couple of methods to interact with the DB (e.g. select, write, etc)
if you only ever have 1 implementation of the protocol, then you could just make functions that operate on the record?
mmh fair enough. Follow-up question: when would you prefer a record over a plain old map if the record does not need to implement any protocol @tatut ?
basically, my use-case is that I want to define some functions to operate on a database. These functions all need to take some configuration data which defines, amongst other things, authorisation filters
can't seem to find the threads now, but this has been asked before - and the consensus seemed to be 'always try maps first, then use records if/when that breaks down'
are there any real time / fps games scriptable in clojure ? (I'm looking to setup a clojure botting contest, and need to find a game)
ok, thanks! Last question: if my “database managment” code is a library, and some bits (e.g. authorisation filters) are the same for all users and throughout the lifetime of the applications, it could be a bit annoyiing/error-prone to pass it as argument to every function of the library. Is it acceptable in this case to store the config in an atom (managed by the lib) and expose a function like
my-lib/configure! config-map to set it?
I haven’t checked the code of
timbre but it looks like they have
timbre/merge-config!, which I assume works this way
Often always passing the same parameters can be tedious, but it pays off in better testability and ability to reason about what the code does
and if you have a global atom, then you can only have one configuration at any given point in time
so I guess a dynamic var is a better solution than a global atom, but probably worse than passing down a param?
but, there is a middle ground where you have 2 arities, one passing in the context and one that reads the atom
users of the lib could always partial apply functions if they don't want to pass the config all the time
(def do-some-lib-thing (partial lib/so-some-lib-thing context)) and act like it isn’t there
but, like always, it depends… sometimes there really is naturally a single global context and the convenience is worth it
yeah, imagine having to pass
System/out and a map of formatting options to every
println call, that would be very, very tedious
I think clj-fakes has a cool solution. It has two namespaces with the same functions: one where there is an implicit context, and one where you pass the context explicitly: http://metametadata.github.io/clj-fakes/user-guide/
(defn foo ([x] (foo @current-context x)) ([context x] ...the code...))) approach is something I’ve used
@hmaurer I wouldn't take timbre as an example in this case. Most logging libraries I've used have some sort of global state
the idea being you very rarely want to log to two places at once in the same code.
DBs on the other hand..Almost every project I've worked on in the past 5 years has had at least one DB. most have 2-3.
So I normalyl recommend putting "state" in a map, and when a function only needs one bit of the state, pass just the state it needs.
@tatut "arities" approach is cumbersome when optional args are needed:
user=> (defn foo #_=> ([x & y]) #_=> ([context x & y])) java.lang.RuntimeException: Can't have more than 1 variadic overload
@tbaldridge thanks! I wasn’t thinking of storing the db connection in that global state though. Roughly speaking I am writing a library to do some things on top of Datomic (data validation, etc), a bit like https://github.com/zcaudate/adi
The global state would be configuration of the application schema (a sort of extension of the Datomic schema)
I'd highly recommend keeping that in a function parameter then. Especially considering that almost all of Datomic can change at run-time and yet the old state of the DB will still exist.
Having things in dynamic vars or in some global atom makes it really hard to have multiple versions of something. And with Datomic it's very common to have a few dozen de-reffed dbs lying around.
@tbaldridge one of my worries is that one of the configuration option is a set of “access polices” which define what can and cannot be done on the data. If I pass this around as a function parameter on every call it seems a bit harder to ensure that the same access policies are passed everywhere
In my use-case I am only planning to use my data-access library on the latest state of the db; I don’t expect it to work on old dbs/schemas
But be that as it may, I don't think I've ever passed this stuff by param and regretted it. Passing via dynamic var or global config has been a pain more times than I can count.
also, the param version is the flexible one - if you code for that, you can adapt to all the others (global mutables, dynamic vars, etc.) trivially if it's actually needed, but the others are not nearly as simple to adapt
@hmaurer I'll second @tbaldridge on this: when we started building our Clojure libraries at work back in 2011, we used global atoms, delays, and dynamic vars because it seem "so much more convenient" than passing all that stuff through parameters. We are still deeply regretting that poor life choice, six years later. Save yourself the pain! Trust me!