Fork me on GitHub
#clojure
<
2015-09-05
>
luxbock02:09:35

@puzzler thanks for the explanation

luxbock12:09:29

is anyone here successfully using clojure-1.7.0-soures.jar that ships with the java source files (for editor support)?

luxbock12:09:15

I'm trying to include it by using [org.clojure/clojure "1.7.0" :classifier "sources"], which downloads the jar when I start the REPL but then crashes with this stacktrace: https://gist.github.com/luxbock/b78272185608adb6b7b8

luxbock12:09:32

I think the issue is that the jar with the source-files doesn't include the .class files, so for example I can't call java -cp ... clojure.main -e to eval with it

luxbock12:09:30

though another project I checked didn't include the .class files in the -sources.jar either, so maybe that's how it's supposed to be

luxbock12:09:23

I think it would be neat if I could jump straight to the Clojure java source from Emacs, and I was hoping that doing this would allow me to do that, but I got stuck here

sdegutis16:09:00

Wouldn't (defn ^:memoize foo [bar] ...) be so cool if it was allowed?

sdegutis16:09:13

Also, is there a more condensed or idiomatic way to do this? (set! (. Stripe apiKey) secret-key)

Alex Miller (Clojure team)16:09:29

@luxbock: the sources jar is not a replacement for the main Clojure jar - it's an additional jar of source files

sdegutis16:09:26

Is this the simplest syntax for setting a static variable? (set! (. SomeClass someStaticField) some-value)

tcrayford16:09:02

@sdegutis: (set! Stripe/apiKey (safe-get env :stripe-secret-key))

sdegutis16:09:14

@tcrayford: Ah that's much nicer, thanks!

zentrope17:09:01

Any advice on how to find a memory leak in a Clojure app? Any "free" tools available? Just use jvisualvm?

sdegutis17:09:25

I'm having trouble modeling a defrecord that wraps a Datomic connection. I currently have start and stop methods which respectively create and destroy a connection, but I don't know where to store that connection, since Records are immutable.

phil_r17:09:55

That's immutable in the clojure sense though (if I'm getting you right)

sdegutis17:09:57

Oh, I see one option. I can return (assoc this :conn some-connection)

sdegutis17:09:15

But it feels weird to return a whole new record from a method.

phil_r17:09:19

I think that works just like a clojure map, i.e. everything you don't change is actually just a very cheap link to the old record.

sdegutis17:09:25

Still feels semantically strange though to return a new "self" instead of mutating self.

phil_r17:09:48

That's probably just because you're used to seeing things in an object oriented perspective, I'm guessing.

phil_r17:09:41

I bet there's a cool talk by Rich Hikey about this somewhere, but I've googled and come up with nothing. Basically it's weird at furst, but later changing things in place instead of returning new ones is the weird thing. 😛

sdegutis17:09:41

@phil_r: I think it's more that it's strange for a method on a defrecord to produce another almost-identical defrecord.

sdegutis17:09:00

Granted this is the first time I'm working with defrecord.

sdegutis17:09:04

So maybe this is a common pattern.

phil_r17:09:21

Well, if you're using records you're probably also using protocols etc so you're in that whole area of Java-ish structure and interop, so maybe that's why it's weird. I'm squeamish with records myself and like plain maps simple_smile

sdegutis18:09:28

@phil_r: Actually I'm not doing any Java interop here, just trying to model a domain using more structure.

jthomson18:09:35

Protocol methods are just functions that dispatch on type. So it's really no different to (assoc {} :a 1) returning a whole new map. Clojure borrows some polymorphic principles of OO but retains its own principle of immutability. In the case of Records, you get the behaviour of a map, which was specifically for the use case you mention: modelling domain (see http://clojure.org/datatypes). This leaves you with the question of 'where do I do my mutation', which Stuart Sierra's Component provides one answer to. In Component you call start on all of your components, producing a new system map in a started state, which you could store in an atom. Sometimes there's a good reason to allow mutation within a component, for example to enable a component to restart itself, in which case you can have your start method assoc an atom, that can later be swapped or reset.

potetm18:09:11

@sdegutis So there's a few things kinda bundled in what you're trying to do. First: datomic connections aren't generally something you want to pass around. They're fairly cheap, so you can make them when and where you need them. Also, unlike a database or a record, they don't represent any concrete value. So that's probably why this feels funny to you. It is a bit odd. (Not to say it's not what you want. I don't know what the overall goal is, so it may be reasonable. There's just going to be some strangeness around values vs opaque objects.)

potetm19:09:52

Second: records/protocols != objects/methods. Protocols are purely for type dispatch. I.e. if the first argument (aka this) is of type-x, call function-y. Other than that they're just like any other function. They take a value and return a value. You can do side-affecty things in them, but, as with all state, you want to try and minimize it where possible. So, all that considered, it would be a bit strange to, say, take a record, mutate some state, and return a new record of the same type to make it look like it's a pure function when it's not. (Not sure that's what you're trying to do, that's just an example.)

sdegutis19:09:52

@potetm: Are you sure you don't mean Datomic databases are cheap? Because d/db is very fast but d/connect is very slow.

sdegutis19:09:53

@potetm: Even with in-memory databases, d/connect is limitingly slow.

sdegutis19:09:54

@jthomson: Thanks. I think I'll go a compromised route, where I give my Database recored a [connection] field and make sure it's always an atom.

tcrayford19:09:06

iirc d/connect is cached after you call it once

potetm19:09:21

@sdegutis I'm pretty sure what @tcrayford said is the case. I know offhand that we create connections prolifically in our app without issue. I'd have to check the docs again to be 100% on the underlying behavior. But either way, it's not at all slow for me. You might want to check in #C03RZMDSH of you're seeing something different.

tcrayford19:09:33

for the record I connect once and pass around everywhere, it fits with how my app is structured 😉

tcrayford19:09:53

for sure creating brand new in memory dbs and then tearing them down (e.g. in tests) is gonna be relatively slow

potetm19:09:50

"For the record". Nice one :)

sdegutis19:09:47

@tcrayford: I should probably clarify that by "slow" I meant that I have about 700 tests that each have d/connect happen at the beginning (with an in-memory database) and it's probably the biggest bottleneck causing my test suite to take about 20 seconds.

sdegutis19:09:24

Thanks everyone I'll try this with your suggestions.

sonnyto19:09:42

hi.... I am trying to setup my project to use a custom build of clojure to debug something in my own code. read-string fails with a cryptic stacktrace. i would like to know what data is causing read-string to throw that exception. I am trying to do this http://jakemccrary.com/blog/2012/03/28/working-on-multiple-clojure-projects-at-once/

sonnyto19:09:48

but with clojure itself