This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-12-30
Channels
- # adventofcode (11)
- # beginners (155)
- # boot (627)
- # cider (64)
- # cljs-dev (110)
- # cljsrn (36)
- # clojure (290)
- # clojure-austin (21)
- # clojure-russia (2)
- # clojure-spec (2)
- # clojure-uk (21)
- # clojurescript (81)
- # code-reviews (2)
- # core-async (33)
- # cursive (6)
- # datomic (9)
- # emacs (1)
- # hoplon (472)
- # instaparse (1)
- # lein-figwheel (4)
- # luminus (9)
- # om (2)
- # protorepl (10)
- # re-frame (10)
- # reagent (48)
- # schema (2)
- # sql (5)
- # untangled (17)
- # vim (1)
- # yada (108)
@mingp: the key reason I can't use mount is its view of singletons everywhere. I often need many instances of the same component. And that runs against the interned nature of vars. Also look into the uses of var alteration in mount, last it looked it made use of global mutation at a fairly low level. That's something I try to stay away from.
Not saying to with Component, there's other options like Integrant (is that the name?) that I think may be better than Component as they take a data-first approach
@tbaldridge What do you mean by "many instances of the same component"? And how does that differ from having differently named components with same/similar implementations shared through reuse?
I've used re-usable components, such as a subscriber that takes the name of a topic. It then gets passed to other components that need to handle those messages.
Actual pub/sub functions are not in the same namespace as the component, but they take the instance as a first param and operate on it.
@tbaldridge: I don't think you're being fair, since we already discussed (https://www.reddit.com/r/Clojure/comments/41gph5/swapping_alternate_implementations_with_mount/cz3azes/) that mount has two modes: where states are kept in vars and where states are kept in deref
ables.
I often need many instances of the same component
usually comes down to I have the same start and stop function (i.e. lifecycle) and I need two components that use these start and stop with different configuration. Nothing stops you to do that in mount.
More of deref'ables and ClojureScript support: https://github.com/tolitius/mount/blob/master/doc/clojurescript.md#managing-state-in-clojurescriptSorry it's been a long time
So yes you can hack around it, but namespaces don't take parameters
So imo any var based approach is going to be limited by that fact.
because you can't write generic code?
@tbaldridge: it's a bit "too philosophical", and I don't think @
or using different components that use the same lifecycle functions (that do take parameters) is "hacking around"
(sorry was eating supper)
Not sure that it's really that philosophical, Clojure is a functional language that prefers functional purity over global mutability. In many cases a deref @
implies mutable state. Mount is no exception. So I find it very odd to propose that we mix mutability through our app. It's a out-of-band input to every function that uses @
and every function that calls them.
I guess that's the part I don't understand about Mount...why would I use so much mutability for something that can be solved by adding a new param to every function.
but i will say that i use mutability (especially thread-bound vars) relatively frequently when they are appropriate
@bbloom sure, but would you wrap every database connection, every server, every message queue, everything in a dynamic var?
@tbaldridge: both Mount and Component help managing stateful resources, that by its nature are mutable. a database connection? mutable. a network socket? mutable, etc. so, yes "`@` implies mutable state" is true, because the state that mount manages is mutable.
@fabrao yes I ahve
i think it is a mistake to ignore vars for philosophical reasons, or assume they are only for dev time
@tbaldridge no, but then again i still haven’t been satisfied with any solution thus far for managing processes & lifetimes in clj
@tolitius sure, the connection is mutable, but my reference to it doesn't need to be
@bbloom I agree, but I very much disagree that the answer to all that is further overloading vars/refs
i will note that while functional code likes the iteration strategy of re-def-ing functions, imperative code, including services, prefers a different strategy
I´m trying to mock a function, is there any way to use matcher for any kind of parameter in provided
?
But I'm more and more in favor of Integrant: https://github.com/weavejester/integrant it's all data, and the library is 200 lines (about 1/3rd of which is comments) ...that's a major win in my book
in lisps of yore, you re-def a var, much as we do today, but in forth you’d make a “mark”
i highly recommend this video: https://www.youtube.com/watch?v=mvrE2ZGe-rs&list=PLXUHm2Eg2p-F_grko9WAypY6ea4CZeNCO&index=1
@bbloom to be honest a real effect system would be the best answer to all this 😉
(My kingdom for a Lisp-Eff-on-the-JVM)
ok, so we are ok with "`@` implies mutable state". now to why var/deref: these states should be able to be started and stopped. one difference from Component or Integrant is that Mount allows restarting parts of your "system", one of many components could be restarted while the system is running. Mount is not a full app buy in, but a library.
@tbaldridge like this `(provided (ssh/execute ...ip... ...porta... ...usuario... ...senha... [...anything...]) => true)`
@fabrao I think you're testing at the wrong layer. I would ask...why do you care that that function is called with those arguments? I'd wager you care about some other side-effect...test that instead. If you test that a function is called with sepcific params, then you're in a bad place when you refactor someday and stop calling that function.
@tolitius all of these libs can be used as little or as much as you want. None of these demand full buyin
@tolitius and they idea of half of my system suddenly restarting underneath me scares me. How does Mount keep that thread-safe?
whell, I´m mocking ssh connection inside other 2 functions, I think it´s usefull for now
but the midje is complain that I have to fix the string in provides, so I did it with
with-redefs
@tolitius actually I'd love to see some sort of documentation on thread-safeness of Mount...how does that work (not an accusation, I'm actually interested)
@tbaldridge, Integrant: https://www.reddit.com/r/Clojure/comments/5gvhi2/integrant_an_alternative_to_component_and_mount/dawqx3u/
@tolitius eh, I'd disagree with Stuart there I think he was being to unkind to himself. The very system we built Component for adopted the library over the course of several months. Whole subsystems existed fine without it while other modules used it.
@tolitius that's a great point you made in Reddit. I'd argue that if Function A calls B and B needs DB then A needs to hand it a DB. That's just basic functional programming. Any other pattern introduces out-of-band communication and that just leads to all sorts of pain. Just look at the implicit parameters mess in Scala.
@tolitius but still I'm wondering about thread safety...how does that work? Can I have two threads refer to two different DBs at the same time? I don't see that by looking at the mount source, but maybe I'm missing something.
@tbaldridge: > they idea of half of my system suddenly restarting underneath me scares me not suddenly, but manually, desirably. > I'd love to see some sort of documentation on thread-safeness of Mount this could be a great idea, what questions are you looking to answer? i.e. mount creates components that can be started and stopped. once started it is up to the start function (which is a custom function that lives anywhere) that, if needed, takes care of multiple threads accessing this component.
So that's my point, dynamic vars in Clojure are thread-bound...which is very important as it allows each thread to not mess up another
So it sounds like Mount puts it on the user to manage thread safety.
> two threads refer to two different DBs I think different is a key here, which means these are going to be different components, and two threads would not be racing for the same reference > it sounds like Mount puts it on the user to manage thread safety I think it is fair to say that, since mount just creates components using custom / user supplied functions, and is able to start / stop / swap (for testing)
but since components = vars in Mount doesn't that mean I now have to create code that matches my architectural state?
So now the structure of my application must now match the vars/namespaces of my runtime, which in turn means I have to tie my architectural state to the file layout of my app. If I want to connect to DB2 and DB1 at the same time, now have to make that model match the Clojure vars and my CLJ code.
This IMO is exactly what Rich was talking about when people asked him about Spec's use of a separate DB for specs...vars are so overloaded it's time we stopped the insanity.
Spec could have been designed so that specs mapped to vars...it's not and there's a reason, I'd submit that same reason applies here.
I think it is better to define these DBs: they are resources. If you need two resources: DB1
and DB2
, these would be two different components / states that will be referenced differently, since the code needs to differ DB1
from DB2
. I am not sure I follow the "fallacy" argument, maybe you can give a more concrete example.
i think spec made the right call by having a separate env, but the unfortunate side effect is that you suddenly have a second class citizen
however, ns-unmap sorta sucks anyway b/c it’s an imperative operation that you can forget to do and wind up in a weird situtation
clojure’s namespaces are in some senses too reified and simultaneously not reified enough
@tolitius to paraphrase Rich, vars exist to give code names. Then we added doc strings, then we added inlining data, etc. Now people want tests attached to vars, now they want examples attached to vars...
Mount adds state management to vars.
All these things could be stored in external DBs. And pretty much all of them should be.
"extrernal" = not in the namespace registry.
@tbaldridge: there’s two elements of this - 1 is whether the data is “owned” by the var, a la metadata including doc strings, :inline, etc
those are independent dimensions - i agree that further overloading in the first sense is clearly bad
Absolutely...the spec problem is a lot like this discussion about Mount. Many people have asked for specs to be parameterized by a DB. That's still "under consideration" according to Stu.
@tbaldridge is there some discussion of that somewhere i missed?
So literally one of the first things people asked when they encountered Spec is...."how do I have this not be mutable and/or have multiple things with the same name based on context"
it's somewhere in this 2hr video, lol: https://www.youtube.com/watch?v=dQcNAscSTSw
IIRC Rich mentioned the var overloading as well in one of his talks.
i think the biggest justification for having a separate logical namespace for specs is that there are LOTS of them
Not really...the justification I've heard from Stu and Rich on several occasions is "stop overloading vars!"
> Mount adds state management to vars I like vars. They serve a "naming" purpose, yes, but they also serve "referencing" purpose. I don't think Mount adds anything to vars from the "language perspective", as do doc strings and meta data. It's a library which uses vars just for naming and reference purposes. The fact that the state behind these vars can mutate is defined by the nature of this state: i.e. a database connection is mutable and the problem mount attempts to solve: adding a lifecycle to mutable external resources.
again, i’m drawing a distinction between the two problems of ownership of metadata and name collisions
@tolitius I think we can probably boil down our argument to this...and correct me if I'm wrong:
I strongly believe that mutable vars are a design-time feature. Any mutation of vars or making things appear to mutate vars should be avoided. Dynamic vars get a free ride since they are thread-safe but I still don't like them
@tolitius I suspect we disagree on that statement ^^
there's not a 1:1 mapping between vars and specs, having unbound vars created just to hold specs would feel much weirder to me than having a separate registry
because vars are made for code (there's a meme in that statement)
although it’s much more likely that specs will be recursive, so you’d have a fair number of (declare foo bar baz) things
And then some vars would contain specs, and some would contain stuff that has spec metadata (sorry, but....ick)
well, what @tbaldridge said. fdefs are just an instance really
side note: i have a toy interpreter lying around somewhere in which environments are like prolog databases. clojure’s vars essentially map to a term like evaluation(sym, value) and other stuff like docstrings etc are similar docstring(sym, “blah blah”)
the result is sorta like having datomic/datascript as the implementation of namespaces 🙂
that's interesting, it sort of implies that the current namespace system is just one level too specialized
Are they immutable though?
I had a variant of Pixie running on a fully immutable effect-based namespace system once...it worked even if it did murder the JIT.
@tbaldridge: I agree with both of your statements in theory. But since we are a bit more practical then IO / read write state transformer monad fans, I do accept and embrace mutation where it is needed. As we talked about earlier, and where this conversation has started: "`@` implies mutable state" => mount has a mode where all the APIs are the same, and no vars are mutated, component state lives in an atom like structure: https://github.com/tolitius/mount/blob/master/src/mount/core.cljc#L107-L116
How often is that dereffed? In other words, if I reset that atom, when does it show up in the functions that use it.
From my understanding of that code it's dereffed every time something uses the component, or at least that's the pattern.
@bronsa it "often" does was my original comment 😉
Promises, deffered, etc. excluded
It's probably not worth it 🙂
@tbaldridge:
> How often is that dereffed?
whenever the "state behind the name" is needed: i.e. (store @db data)
> if I reset that atom, when does it show up in the functions that use it
you don't really reset!
it directly, it only gets reset whenever (mount/start)
/ (mount/stop)
are called. Since it has CAS semantics (i.e. atom), other functions will see it whenever the change is applied (it is either started or stopped)
so in terms of syntax and (logical) namespaces, the defstate macro doesn’t seem insane
b/c to do much better would require a fair amount of integration with the repl or whatever
@bbloom that's it though...it doesn't need to be this way, we could just pass the DB into the function as a parameter.
In one approach the code may be a bit more verbose, but I'd take that any day over any sort of implicit parameter. Implicit parameters hide information. Information I now have to keep in my head.
@bbloom: the idea behind a singleton is that an external resource is a singleton. as to thread safety, I think it depends on the usage. The intended usage is to start and stop components of an application. Usually, in 99% of time, it is a single call to (mount/start)
and after everything is done (i.e. shutdown hook, end of life), a call to (mount/stop)
but if you need to get the ctx to someplace new, you have to make a cross-cutting change to every function in between
in terms of the “open systems” idea, implicit parameters give significant expressivity
@tbaldridge > we could just pass the DB into the function as a parameter you still do that with mount. it's a choice that you have. if you keep all these resources at the edges of your app, they just get passed into functions as arguments
@tolitius then why store them in a var at all in that case?
in terms of clojure as it stands today, i agree with tbaldridge in terms of “just make a context parameter” and also make that the default approach
sure, we all do. And I use dynamic vars quite often, but more as a global accumulator when I'm using the return value of a function for something else.
Well, I use mount in many projects. I´ve never had to change the
defstate
, I use other things to do this, it´s read-only, and in tests I use before -> mount/start and after -> mount/stop@tbaldridge for that, i use this pattern: https://gist.github.com/brandonbloom/b8a9ace37b93a6ff369d64e821a6e5ff
@fabrao that's not really what we're discussing. defstate creates state, and that state is mutated whenever you call start/stop
my bigger problem w/ components/subsystems in clojure is dealing with failure - missing log output or silent exceptions and the like are KILLER at dev time
> then why store them in a var at all in that case?
(var or an "atom") because you need to get to these references somehow. In Clojure, we get to references by (require [app.foo :as foo])
. With mount this stays. And there is no IoC as in Spring / Component, everything still Clojury: you need a reference in this namespace? require
it.
i’ll also say that some things really are singletons & it’s perfectly valid to use dynamic vars in that way
instead of passing a connection around, you may pass around the name of the db for example
personally, i prefer systems like that over object-oriented ones that pass around little closures
@bbloom: interesting (about failures). could you give an example of a silent failure that behaves any differently when using components/subsystems?
@tolitius just the other day i did something like (future (while true (handle (.take q))))
and the future failed, silently of course
did you have:
(Thread/setDefaultUncaughtExceptionHandler
(reify Thread$UncaughtExceptionHandler
(uncaughtException [_ thread ex]
(error ex (str "uncaught exception in thread: " (.getName thread))))))
in placeso say, you used Component, how would this silent error manifest itself differently?
just trying to understand this: > my bigger problem w/ components/subsystems in clojure is dealing with failure - missing log output or silent exceptions and the like are KILLER at dev time
you probably mean that there is no supervisor tree Erlang like solution that would keep all this components supervised in Clojure, right?
i dunno what it does or doesn’t do in this regard. i just find the primitives lacking for async errors
although I don't think the scope of the problem (that Component or Mount attempt to solve) included async supervision, but more of a state organization and lifecycle management
Async error are really hard
yes, I can feel the connection. although this would require a lot of "different vertical" thinking time
The best system I've worked on in that space just killed the entire JVM when it hit a bad enough error. Worked quite well in a distributed system. But that was a rather extreme way to handle errors
All modules are immutable
You have to send a upgrade message to a actor and the it bootstraps itself in the new module
In Erlang all your state is in locals 😉
i’m a fan of this idea too: http://250bpm.com/blog:71
cancelation and shutdown are really frickin' hard when you can’t just kill a process tree
Which is why we started with killing the JVM then added exceptions to commonly known "safe" errors
i’ve written a fair amount of Go, and it’s quite apparent to me that CSP is totally busted for shutdown and failure
this piece looks very mutable to me: http://erlang.org/doc/apps/odbc/getting_started.html#id61120 🙂
@tbaldridge is there a decent default solution for printing errors in core async threads?
@bbloom > yup, i’ve read armstrong’s thesis Whats the name of the thesis?
@drewverlee "Making reliable distributed systems in the presence of sodware errors” - http://erlang.org/download/armstrong_thesis_2003.pdf
That's because Erlang message boxes are mutable
So stuff like the isn't driver there is storing the mutable state in an actor
*odbc
right, just interesting to see how some of the external resources are accessed in Erlang: directly by referencing other modules (given that they are exported of course).
I'm interested in what that start fn does as the only mutable thing in Erlang is actor message boxes
@bbloom: I am thinking a bit more about enabling component lifecycle (i.e. start / stop) and supervising their runtime state, and I think they are in fact different concerns. "managing lifecycle" would be an overloaded phrase (used by me 30 min ago 🙂 ), so I would say mount/component enable / provide start and stop lifecycle events to components.
It feels that something entirely different could then truly manage or supervise these component at runtime, and use mount/component to restart the ones that were stopped due to a failure. with mount it would be really simple since it is able to restart any part of the application i.e. (mount/start component1 component2)
the problem is that the “dependency graph” and the “supervision graph” can/should largely coincide completely
And once you start automatically restarting things you really have to think about thread safety, so all functions have to become channels, or you deref state once, or something like that
That's a conversation I'd love to have since I've sat and thought about it for more hours than I can count, and I still hate all of my ideas.
@bbloom sure cooperate, yes. but it could be solved (and it feels right if it is solved) by two different libs @tbaldridge: > I'm interested in what that start fn does as the only mutable thing in Erlang is actor message boxes would not call to start just call init? http://erldocs.com/18.0/stdlib/gen_server.html#init/1
@tbaldridge: > once you start automatically restarting things you really have to think about thread safety could you lock on "restart by the supervisor"? performance would degrade, but if it came to this case, it would mean a certain component or a group of components were stopped (or in unsatisfactory "health") anyway
Usually it s avoided to block in init. "Erlang in anger" has a good guide about this stuff
(repeat (f)) is equiv to (let [x (f)] (repeat x)) // now, is there a way to generate a ( (f) (f) (f) (f) (f) (f) ... ) ? In particular, here, f = gensym -- so I want it called multiple times.
@doglooksgood unlikely, given how easy it is to write (partial = x)
🙂
I'm observing transient maps to be much slower for reading than regular maps, is this a known issue? Is there something wrong with my benchmark below?
I'm trying to write a fast transient version of clojure.core/update, but at this point I'm wondering if it's worth using transients at all for this purpose..;
@qqq (repeatedly f)
Transient data is initially essentially shared with the non-transient data it came from. So I'm not surprised the access time isn't faster. Updates, however, are the selling point for transients and should be much faster.
@joshjones access time is worse than 'not faster', it's more than twice slower 😕
Does any know of a Clojure library for manipulating nested datastructures other than Specter? I heard talk of one at Clojure Exchange but the name isn't coming to me now.
clojure.walk ?
@dacopare I remember there was a library where you could provide before / after datastructures and it figured the transformation out by itself, but unfortunately I do not remember the name
wow that sounds cool, @sveri
Hello, I am trying to run a Clojure script with:
java -cp clojure.jar:script-utils clojure.main script.clj
where script-utils
is a directory containing util/test.clj
file (with a correct ns declaration) and script.clj
does (require util.test)
but the execution fails with java.lang.ClassNotFoundException: util.test
Are uncompiled clj files on classpath not supported for scripts invocations with clojure.main
?
(I also tried to run it with java -cp clojure.jar:script-utils clojure.main -i script.clj
but the result is the same
Should be (require 'util.test)
, @piotrek
@dacopare my library Odin allows you to query data structures and then run updates on specific areas of the structure as defined by a query (think SQL or Datalog for Clojure data): https://github.com/halgari/odin
@pesterhazy @sveri @tbaldridge Thank you for your suggestions!
Hi. Apologies if this isn’t the right place to ask this question, redirects welcome. I’m suddenly getting a class not found exception when I try to
lein run
my project.
Exception in thread "main" java.lang.ExceptionInInitializerError
at clojure.main.<clinit>(main.java:20)
Caused by: java.lang.ClassNotFoundException: monger.core, compiling:(cavalry_admin/data.clj:1:3)
My project.clj includes the dependency [com.novemberain/monger "3.1.0" :exclusions [com.google.guava/guava]]
and the file mentioned requires the library like this: ( (:require [monger.core :as mg] …
.
I can see the library in my .m2 directory:
~/dev/cavalry-admin # ls ~/.m2/repository/com/novemberain/monger/3.1.0
total 128
drwxr-xr-x 7 rodfitzsimmonsfrey staff 238 30 Dec 07:40 .
-rw-r--r-- 1 rodfitzsimmonsfrey staff 178 30 Dec 07:40 _maven.repositories
-rw-r--r-- 1 rodfitzsimmonsfrey staff 44450 30 Dec 07:40 monger-3.1.0.jar
-rw-r--r-- 1 rodfitzsimmonsfrey staff 40 30 Dec 07:40 monger-3.1.0.jar.sha1
-rw-r--r-- 1 rodfitzsimmonsfrey staff 7257 30 Dec 07:40 monger-3.1.0.pom
-rw-r--r-- 1 rodfitzsimmonsfrey staff 40 30 Dec 07:40 monger-3.1.0.pom.sha1
drwxr-xr-x 4 rodfitzsimmonsfrey staff 136 30 Dec 07:40 ..
.@credulous have you tried lein clean
?
Nope! Didn’t know about that… I ran lein deps, and also changed the lib version. I’ll try that now.
@credulous my guess is a typo somewhere
what did you change since it last worked?
also try rm -rf ~/.m2/repository/com/novemberain
and re-running
and see if it fetches the jar again
you can check that the jar you have actually contains the class/ns with jar tvf ~/.m2/repository/com/novemberain/monger/3.1.0/monger-3.1.0.jar
I’d expect it does contain what you want in which case… try
lein deps :tree
to see whether something is overriding your dependency
@credulous do a lein classpath
and see if it includes the monger jar
@val_waeselynck : thanks! (re repeat vs repeatedly)
is there a way (besides rewriting the function as macro) to say: I want this function inlined instead of having it as a function call?
@val_waeselynck I have done some research regarding your problem. The TL;DR version is this: the slow part of the transient lookup is when you try to get
a key that is not in the transient array map, when the key is a keyword and the map does not utilize keywords for keys. (with more details below). If I do:
(def arraymap-1 (transient {:abc 1 :def 2 :ghi 3 :jkl 4 :mno 5 :pqr 6}))
and retrieve an unknown key using (get arraymap-1 :z)
then it is a 17ns
operation.
However, if I define the map with no keywords, but all numbers for keys and vals:
(def arraymap-1 (transient {5 1 3 2 7 3 8 4 9 5 11 6}))
Then a (get arraymap-1 :z)
takes 270ns. Crazy. If I do a (get arraymap-1 2389752346)
, then it's 64ns, much better.
Persistent and transient hash maps are fine, and persistent array maps are fine. The issue is the transient array map when accessed as above. There's more to this story but I don't have time today to research it any further. My curiosity took me this far but you'll have to take it from here. I suggest following the trail into doValAt
and valAt
in both the persistent and transient implementations in [PersistentArrayMap](https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentArrayMap.java).
"deftype is for programming constructs and defrecord is for domain constructs" <-- this makes no sense to me, one is about building up the language, and the other is about domain specific? I don't get the distinction
qqq: deftype lets you create something java code can access easily, defrecord makes something with sensible behaviors for usage in your own code
so deftype is an implementation detail, defrecord is for modeling things in an idiomatic clojure manner (I think...)
what that quote means by “programming constructs” is that deftype lets you create new abstractions
by contrasting that with “domain constructs” it’s saying that you probably don’t need new abstractions to model data
you usually don’t need records to model data either, but there are some times it is useful to have a unique type for dispatch
the summary is this: use maps for pretty much everything, records if you need dispatch (and only if your record will coexist with dispatch against arbitrary types!) or explicitly typed fields for perf (and you measured that it actually helps!)… the only use deftype if the abstraction you have is really really not plain associative data
@qqq another way to think of it is if you are going to be doing standard hashmap-like operations on the target, then defrecord makes a lot of sense. I use defrecords for a lot of purposes. Aside from something declarative, sometimes I use it as a faster map (with some costs) or a map that I can attach a protocol/detect using a protocol. For instance, you can use a record and a protocol as a faster alternative to multi-methods in some situations like conversions or encoding/decoding for a codec or you can use it to implement a protocol that has naturally grouped functions with multiple implementations. Deftype (which also uses protocols) on the other hand as stated tends to go well with working with Java and makes a lot of sense if you're not going to be doing things like adding keys to it. I tend to use deftype a fair bit when I want some kind of resources where representing it as a map makes no sense or would be annoying (i.e. Java API client or something like that). There's no reason you can't take something you defined as a deftype and put it into a map or a record anyway or vice-versa. I would say deftype is still idiomatic and has a lot of uses. Look at clojure itself for some examples, as well as its cousin reify when you need something anonymous or with less functionality (a fair amount of use of this in core.async for example).
I would agree with pretty much everything @bbloom said.
Of course as is the case with anything done for performance reasons alone, measure first.
@qqq I’ll give you two concrete examples of deftype
from our (production) code base...
We deftype LazyAtom
as a variant of Clojure’s Atom that defers evaluation of its initialization until first use (we use it for mutable caches so we can defer the seed creation)
And we also use deftype
along with definterface
to create functions we can add Java annotations to, for tracing function calls in New Relic.
@qqq: I tend to mostly use maps for data and deftype
s for polymorphic dispatch. defrecord
s complect things (in my mind) for several reasons:
* they can't be called as function i.e. ({:a 42} :a)
* assoc
on a record returns a record, dissoc
returns a map
* the way they are usually used (extending protocols) they complect data and behavior
deftype
is simpler, consistent and greatly named: it is a "new type". There is no expectations of deftype
being a map, hence no function / assoc/dissoc inconsistencies, there is a clear expectation that it could encapsulate data, and it should not be accessed directly, etc.
I describe that here: http://seancorfield.github.io/blog/2013/05/01/instrumenting-clojure-for-new-relic-monitoring/
Anyone know the best clojure graph db?
i cant speak to best but i've used neo4j from another lang and it looks to have good clojure docs
hello people, can someone please explain to me why this (transduce (map #(* % %)) - 0 [2 3 5])
results in 38
? before seeing that I expected a transduce like that to have the same result as (reduce - 0 (map #(* % %) [2 3 5]))
which returns -38
it seems the transduce version does a last call to -
with -38
(the last accumulation), making it reverse, is that the expected behaviour?
@wilkerlucio yes, it's the expected behavior. The last call is done to do any flushing/finalization that needs to be done by the transducer pipeline. Useful if you're doing things like transients that need a final step to turn them back into persistent data.
thanks for the clarification @tbaldridge
@josh_tackett That really depends on what you want from the DB. I wouldn't worry about Clojure so much as what the DB does to meet your needs as most graph DBs have wildly different performance and scalability characteristics and use-cases. As long as it has a Java bindings which most do, it is minimally useful from Clojure. Ideally of course it would already have Clojure bindings. It's been awhile since I picked a new graph db, but Datastax Enterprise Graph, Orient DB, and Neo4j are popular choices these days. If your needs are relatively simple or you can make compromises in performance, reliablity, built-in algorithms, etc., then you can essentially build a graph DB on top of most databases, many of them have decent bindings from Clojure - ex: Datomic, Cassandra, Elasticsearch, Redis all can host rudimentary graphs (ex: simple adjacency list-based queries) but won't meet more complex needs unless you build out what amounts to a product on top of them.
Regarding neo4j, it has a lot of support and documentation, so if anything it's a good place to learn. I haven't used it in a year or two, but my experiences with scaling it aren't good compared to others. If your datasets are small though it performs well enough and is probably the easiest of pure graph databases to get started using. A bit off your question, but I'd also ask yourself if you really need a graph database at all before you dig too deep. There are many justifications, but I've heard too many people wanting to use them when their problem wasn't really a graph problem. The issue is a graph can pretty much represent almost anything so it's easy to shoehorn things in that will do better with other solutions.
You can also use GraphX which is part of Spark. It's possible to use Flambo which has Spark bindings to do this, just requires a bit of tinkering last I checked, but maybe that changed.
Quick Q: in Cheshire, how do I get (generate-string)
to output json map keys like item:
instead of strings like "item":
Ah yes.
var config = {
mode: "fixed_servers",
rules: {
singleProxy: {
scheme: "https",
host: "host",
port: parseInt("22225")
},
bypassList: [""]
}
};
yes, you can prove that to yourself easily by typing (source and) or (source or) in your repl