Fork me on GitHub
#clojure
<
2016-01-20
>
Alex Miller (Clojure team)00:01:28

if you scroll up slightly from there, there are docs on how to enable compiler options including direct linking

bcoop71300:01:00

I'm going through the Living Clojure book, and I'm a bit lost on a topic. Say I were to build a tradition CRUD/todo list backend. What would I use the following for: Atoms, Refs and Agents?

bcoop71300:01:33

Seems like atoms would be used anywhere I need mutable state?

seancorfield01:01:35

@bcoop713: You might not use them anywhere… Once you really get into using Clojure, you’ll be surprised at how rarely you need mutable state inside the program.

seancorfield01:01:27

For example, we have about 30,000 lines of production Clojure and only 30 atoms — and those are nearly all just caches. We have just 3 agents, and no refs at all.

bcoop71301:01:18

gotcha, are they mostly used as a last resort?

donaldball01:01:43

I can’t find a non-pithy way to say it: atoms/refs are mostly used when you need mutable state 😛

seancorfield01:01:51

Mutable state is a last resort 😸

donaldball01:01:09

Your crud/todo list backend could have its database state stored in an atom, fer instance

seancorfield01:01:32

(as long as nothing else is likely to modify the DB under you)

donaldball01:01:04

Or you might implement a database connection pool using an atom. It’s hard to give a general principle for their use except, as sean says: lightly?

bcoop71301:01:18

interesting. And under the covers, is it actually mutating state, or does it use some sort of state monad?

seancorfield01:01:24

When you swap! or reset! an atom, it updates the value inside the atom, atomically, so it’s "real state".

jaen01:01:21

It's about as real a state as the state you would store in postgresql is, MVCC and all.

seancorfield01:01:54

You just really don’t need it much.

bcoop71301:01:56

cool, so I'm jsut going to ignore it until I get stuck.

jaen01:01:35

Yeah, that's usually how it turns out in practice.

jaen01:01:58

For example if it's a state you need to keep across function invocations like cache or in-memory database - then an atom/ref might make sense.

jaen01:01:45

If it's a - say - iteration state then you can do recursion or use the loop macro (which is sugared-up recursion).

jaen01:01:47

Also an indication you might need an atom or ref if you need to coordinate something, possibly across threads. Access to atoms is guaranteed to be serialised, and access to refs can be wrapped in ACI transactions.

bcoop71301:01:04

is that if i wasn't using core.async or would there be a use case to use atoms along with channels?

jaen01:01:11

Depends on your use case, I suppose. If you need to accumulate what you get over the channel somehow, atoms and refs sound more sensible than using a loop parameter or something. If you just need to react as-you-go and don't need to keep things around, you can do away with atoms.

jaen01:01:57

The difference between channels and reference types is a bit akin to the difference between a queue and a database, just in-memory.

bcoop71301:01:38

interesting, that helps

jaen01:01:04

Like all analogies, it's certainly approximate and can lead to a bit confusing intuitions - monads are not burritos - after all, but I think it's a good first-degree approximation of their respective niches.

jaen01:01:39

And when you start using them in practice the intuition will get more clear, I suppose.

bcoop71301:01:22

one way to find out simple_smile

perdue04:01:53

If I am running emacs and evaluate something like (in-ns ‘my-namespace) in a buffer, if I evaluate (clojure.core/ns-name clojure.core/*ns*) in my CIDER REPL, the namespace remains user. But, obviously, if I evaluate (in-ns ‘my-namespace) directly in the REPL, the namespace changes. Why does this work this way?

bradford04:01:51

Did some research, seems like the only clj graph library + graph query language that works is neo4j. ogre/titanium are woefully out of date and/or depend on writing Java. Loom is amazing but doesn't really have a query language.

bradford04:01:57

Too bad about Neo4j's licensing tho.

danielcompton05:01:31

@alexmiller: how do you enable direct linking in Leiningen/Boot?

Alex Miller (Clojure team)05:01:55

@danielcompton: in lein you'll need :jvm-opts ["-Dclojure.compiler.direct-linking=true"]

Alex Miller (Clojure team)05:01:06

(I think, doing that all from memory)

Alex Miller (Clojure team)05:01:12

in boot, don't know off the top of my head

debug06:01:01

so when will the lein repl start using the latest version of Clojure?

jsa-aerial07:01:48

@alexmiller: Aha - yes, I see it now. Thanks!

martinklepsch10:01:56

@danielcompton: BOOT_JVM_OPTIONS for boot

slotkenov11:01:31

how would you remove all leiningen dependencies, in order to check if a clean checkout and the a lein run would work as expected?

slotkenov11:01:07

I moved /.lein/indices to /.lein/indices-old

slotkenov11:01:25

lein run doesn’t seem to pull any dependencies though

pguillebert11:01:36

delete your ~/.m2 directory

pguillebert11:01:46

maven stores all deps locally there

slotkenov11:01:29

maven, of course!

shaym11:01:58

anyone using slamhound ?

jan.zy12:01:06

me! works as a charm

danielr12:01:47

I'm trying to use a protocol I wrote in clojure in my java project. I built the uberjar and copied it in my java projects classpath. But when I try to compile the java project using plain and simple "javac -cp mycloj.jar Main.java" I get a "cannot find symbol".

danielr12:01:23

It does find the other dependencies from the uberjar though, like clojure.lang.IFn.

danielr12:01:25

Any idea what I'm missing here?

nberger13:01:17

@shaym I use slamhound too

shaym13:01:24

nberger: tx i was able to resolve the issue (i placed the slamhound dep, in :plugins instead of :dependencies)

shaym13:01:24

jan.zy: nberger its supposed to fix missing require ns , but i only see it remove unneeded ones so far

dm313:01:47

@danielr how are you using the protocol? from java?

danielr13:01:37

I'm implementing the resulting interface. But it cannot resolve the import, whereas it has no problem resolving i.e. clojure.lang.IFn

nberger13:01:23

@shaym it fixes missing requires... perhaps you are hitting an edge case? what's not fixing?

shaym13:01:44

@nberger: I had a file which was using some fns from another file in the same dir , but slamhound didnt add the needed require , maybe it adds the ns when the require already exists

danielr13:01:21

@dm3 its just a usual java project setup with src and lib. The protocol interface is in the uberjar.

dm313:01:56

what's the ns of the protocol?

nberger13:01:38

@shaym: that should work. except for example if the fns are also found in the default :refer's from clojure.core for example... or if there's a compilation issue in the other namespaces...

dm313:01:00

@danielr, make sure you replace - with _

nberger13:01:06

IIRC it does kind of a brute force search for the symbols on every reachable ns, and your other ns should be included in that search if it compiles correctly

shaym13:01:34

@nberger: yes i did have some compile errors , ill retry it after those are fixed , tx

danielr13:01:19

@dm3 I already got rid of all the dashes in my clojure code 😞

dm313:01:46

do you see the class that you're importing in the jar file?

danielr13:01:24

And eclipse even offers me the import

danielr13:01:55

But afterwards it marks the import and says "cannot be resolved"

danielr14:01:08

@dm3 this is my decompiled interface:

dm314:01:24

is the class in the right dir? slack/slackapi/SlackActions.class ?

dm314:01:36

just going through the checklist simple_smile

danielr14:01:55

simple_smile yup, it is

dm314:01:45

what's the full error?

danielr14:01:25

When I don't include my uberjar in the classpath it also complains about clojure.lang.IFn not being found

danielr14:01:13

Would it help to see my project.clj?

danielr14:01:55

@dm3 maybe have a quick look at my clojure code? Its hosted at github: https://github.com/drosowski/slack

danielr14:01:27

Its not the latest version, but I only changed the methodnames on the protocol (removed the dashes)

dm314:01:15

yeah, this is strange

danielr14:01:49

Different java versions? But then I would get major/minor version error, right?

danielr14:01:23

Ok, thanks for your effort though, I appreciate it!

dm314:01:25

although you can load it dynamically (Class.forName)

dm314:01:44

so it's on the classpath, just not visible during compile time for some reason

danielr14:01:09

Is that an assumption?

danielr14:01:16

But this way I cannot work with the interface

dm314:01:43

of course

dm314:01:51

I'd try minimizing the problem

dm314:01:57

as much as possible

danielr14:01:24

@dm3 I never had the case that a class is not found during compile time, but is available at runtime. Only the other way round

jindrichm14:01:02

Can you dispatch a multimethod on multiple arguments while preserving their isa? hierarchy? Should I compute the lowest common ancestor of the arguments in the dispatch function and dispatch on that?

oskarth15:01:09

For people using system/components, how do you deal with redefining Records? It seems like quite a common thing, especially as you are building out your app with dependencies for components, etc. Right now I'm forced to re-start my REPL to get the new record into memory. Am I missing something?

jcromartie15:01:26

Sometimes you can get away with fully reloading all namespaces.

jcromartie15:01:54

And tossing all references to the old record. That usually means starting all components from scratch again to be safe.

timvisher15:01:51

so how does the new socket server interact with nrepl?

roberto15:01:04

I used the reloaded workflow, no need to restart repl with that.

oskarth15:01:07

jcromartie: If I run (stop) then (start) again anything defined in defrecord is still stale.

oskarth15:01:50

hm, same here roberto. So if you add a (println "foo") in some record's start fn, run (stop) and (start), does "foo" show up then?

roberto15:01:16

I normally don’t use println inside start, I use log, and it does show up.

roberto15:01:43

you can test in the repl if it is working by just instantiating and calling start.

oskarth15:01:13

so function calls work because functions are evaluated at runtime

oskarth15:01:27

thanks @jindrichm, will read through it

oskarth15:01:13

so it seems to mostly advocate mount, which might be a good idea, but doesn't really help dealing with components in a more sane way

roberto15:01:30

I tried mount, and it is easier to get started, but I’ll be sticking to component. With mount I found it easier to make a mess.

oskarth15:01:43

one thing I learned is that defining the interface functions generically means you can usually avoid making too many changes

oskarth15:01:25

I feel like it should be possible to override/unalias the records somehow

roberto15:01:07

I don’t think you can, because they are instantiated.

oskarth15:01:07

it seems to clash with exploratory programming a bit then, from my understanding

yogthos15:01:07

@roberto: you don’t need to restart the repl with reloaded, but you can’t keep any state there either

yogthos15:01:17

it’s much closer to TDD in style

oskarth15:01:26

@yogthos: hm, so it seems like you are saying it is possible to change the record of a component and restart the system without restarting the repl?

yogthos15:01:43

I often use the REPL as a scratch pad

yogthos15:01:02

so I might load some state I need to develop a feature

yogthos15:01:04

and work with it

yogthos15:01:14

for example, I’ll def some sample data in the session

oskarth15:01:17

right, but that's a different case. I still don't understand how to change a record and not restart the repl.

oskarth15:01:58

(for those types of things I'd just use cider-eval-buffer or eval region in a (comment ...) section)

yogthos15:01:58

and yeah I don’t think reloaded obviates the need to restart the repl, you just do it less often

oskarth15:01:49

so @roberto is right in saying I don’t think you can, because they are instantiated`.? I'm confused. I don't know enough about how records are implemented and evaluated to have a good mental model of this.

oskarth15:01:20

it seems particularly weird to me because so much of using system and components consists of actually designing the components interface, which leads to a lot of repl restarts, hence the feeling that I'm missing something

roberto15:01:01

components are the outer interfaces or ports of your app. Also, not everything should be a component. I normally start developing inside -> out.

roberto15:01:43

The inside or inner layer, I can just start working on it in the repl without needing component. So I have never had the need to rebind a component.

oskarth15:01:25

that's a good point

yogthos15:01:55

note that you can use protocols with mount as well

oskarth15:01:07

I think that's mostly what I'm doing, but I'm converting things from a non-component workflow to a component workflow, and mapping out dependencies and such

yogthos15:01:21

the protocol can define a resource, and then the instance lifecycle can be managed by defstate

oskarth15:01:50

it's possible my components aren't generic enough and thus requires a bit too much fiddling compared to what components/systems is optimzied for

roberto15:01:05

yeah, if you started without component, and your codebase got large, it can be tricky to shoehorn component in there.

yogthos15:01:07

I think it’s much easier to fit mount into an existing app than component

roberto15:01:44

I normally add component as soon as I have more than two systems that need to interact

oskarth15:01:29

code base is not too big, just a few hundreds of lines of code, and 4 systems

oskarth15:01:07

to be fair, a bunch of effort is just on learning how components works with DI etc

roberto15:01:25

then it should not be that difficult. Also, you can do everything in the repl, just assign the component to a var

roberto15:01:03

(.start MyComponent) returns a component, and you can inspect it and pass it around if you assigned it to a var

oskarth15:01:25

hm, maybe that's what I should be doing instead

roberto15:01:27

and you can redefine the var if you make changes to your component

oskarth15:01:32

right now I'm running go/start/stop

roberto15:01:35

yeah, that is what i normally do when I start

roberto15:01:48

I rarely do the refresh cycle

oskarth15:01:49

how does that work with DI?

tolitius15:01:04

@roberto: > I found it easier to make a mess can you share a bit more of you experience which lead to this reasoning? you can do it in a #C0H7M5HFE channel if it is more appropriate

roberto15:01:23

it was easier to just say: I can just have a giant atom here and mount it, and have it accessible everywhere.

tolitius15:01:14

@roberto: resources without a lifecycle?

roberto15:01:53

Component makes that explicit: A component has a lifecycle

tolitius15:01:04

so does a defstate

oskarth15:01:36

interestingly, https://github.com/weavejester/reloaded.repl/blob/master/src/reloaded/repl.clj#L55-L57 seems to solve the use case of adding stuff in the record, as far as I can tell

tolitius15:01:58

I am more interested in "lead me to think I'll make a mess with it" line of reasoning, if you can share of course

oskarth15:01:52

so maybe that's all there is to it?

roberto15:01:20

yeah, you can use reset and it will do that: reset your system with the new definitions

tolitius15:01:10

@oskarth did you have suspendable components? because all the reset-all does besides suspending is just a namespace refresh

oskarth15:01:11

so isn't that the answer then?

oskarth15:01:36

I didn't instrument them in any special way, no

tolitius16:01:06

@oskarth: have you tried to do (refresh) from REPL yourself?

oskarth16:01:39

so I assumed component restart took care of that, but it seems like it doesn't

oskarth16:01:58

so the answer to my question then is: use reset, and this mean that records can be changed.

roberto16:01:25

i think I don’t understand what you are really trying to do

oskarth16:01:31

not instanzied ones but the ones that system needs

tolitius16:01:34

component is a bit different from "reload". reload is done with tools.namespace

oskarth16:01:44

My original question was: "For people using system/components, how do you deal with redefining Records? It seems like quite a common thing, especially as you are building out your app with dependencies for components, etc. Right now I'm forced to re-start my REPL to get the new record into memory. Am I missing something?"

roberto16:01:06

you can reset

oskarth16:01:23

@tolitius: yeah I know, but I falsely assumed component took take it (why wouldn't it)

roberto16:01:29

if you ever feel the need to restart repl, (reset) should be enough

tolitius16:01:31

reset is not a part of component

oskarth16:01:32

yeah apparently roberto but that's not what you said when I asked 😛

roberto16:01:42

I didn’t understand your question

tolitius16:01:48

it's just a convenience function that refreshes and restarts

roberto16:01:14

I thought you wanted to maintain the state of your app, and be able to redefine a single record, and swap it from underneath all the other components that depended on it

oskarth16:01:28

components helps me maintain the state of my app

roberto16:01:57

(reset) will just restart your entire system, not an individual component.

oskarth16:01:07

for example, refresh doesn't help you with external libraries, so I thought records by a certain name weren't affected by whatever start/stop did.

roberto16:01:08

I thought you wanted to do the latter

oskarth16:01:30

stop and start restarts your system too though

oskarth16:01:34

semantically speaking. No?

roberto16:01:55

(reset) just calls both stop and start

tolitius16:01:09

the problem with (reset) in REPL is with records that were previously defined in REPL. you generally should not see problems with (reset), unless something does not compile, then you have to do (refresh)/(refresh-all) which also does not work sometimes, usually when components have incorrect destructors..

oskarth16:01:11

that's the point, that it doesn't

oskarth16:01:47

I thought it did

oskarth16:01:34

@tolitius: I don't understand, how is calling refresh/refresh-all different from reset? reset(-all) calls those.

roberto16:01:40

yeah, if you have a ring component, and you don’t stop the server in the stop Lifecycle of the component, then reset will not work

oskarth16:01:58

because of the :after 'reloaded.repl/resume?

tolitius16:01:01

reset is just a wrapper around stop/refresh/start

tolitius16:01:18

but sometimes you need refresh-all

oskarth16:01:31

reset-all calls refresh-all

roberto16:01:58

honestly, for me it just works, I don’t spend time trying to figure out why. As @tolitius mentioned, when reset fails, I do reset-all, but it rarely happens to me.

oskarth16:01:06

yeah, I assume start/stop are properly implemented. I'm just talking about the record.

tolitius16:01:35

I guess the confusion is the weavejester/reloaded.repl and how to just use clojure/tools.namespace directly

oskarth16:01:40

argh, lots of misunderstandings. The answer was simply reset/reset-all rather than just stop/start.

tolitius16:01:27

@oskarth: could you provide an example of what does not work? would it easier to help/discuss

oskarth16:01:38

no, it does work

oskarth16:01:04

my confusion came from not understanding that start/stop doesn't call reset

oskarth16:01:28

when I asked what I was doing wrong no one said reset, and I later found by experimentation and looking at reloaded.repl source code that my use case works

oskarth16:01:29

that's all

roberto16:01:21

I’d recommend reading the clojure/tools.namespace README if you want to get a better understanding. It was very helpful when I was starting off with the reload workflow.

tolitius16:01:55

@oskarth: yes, sure. it is always best to go to the root (i.e tools.namespace), rather than try to understand how it's wrapped

oskarth16:01:04

more misunderstandings! I must not be expressing myself very clearly. The problem was not with not understanding how refresh works, but in thinking that component/reloaded already did that in start/stop.

tolitius16:01:33

@oskarth: all good. this is neither simple nor easy, and does require time to get simple_smile

oskarth16:01:37

it doesn't matter though, everything is fine, the answer is to use reset when changing records

oskarth16:01:16

If I had read http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded more carefully I would've found this out earlier (ctrl-f heart)

tesseract17:01:16

is there a best practices list/guide for doing micro services in clojure?

val_waeselynck18:01:00

@tesseract: I think the SoundCloud and Netflix guys published a lot of stuff about precisely this

vanrysss19:01:23

As far as books for learning clojure go, if you were to buy one which would it be?

jaen19:01:58

I liked "Programming Clojure" (the swan book) as an introduction to the language.

csmith19:01:05

I liked the swan book too. I’ve heard good things about “Living Clojure”. I’ve read “Clojure for the Brave and True”, which was really good. Was hard to gauge because I’d already read an intro at that point.

bfabry20:01:53

is this still the current solution if you need a gen-class to reference its own name in either a return value or a type hint? https://groups.google.com/forum/#!searchin/clojure/gen-class/clojure/A9Si6Ow581U/sstYR15uBgAJ

Alex Miller (Clojure team)20:01:40

if anyone didn't take the Stackoverflow developer survey - it ends in a few hours https://www.surveymonkey.com/r/so-2016 say nice things about Clojure! :)

shaun-mahood20:01:54

@vanrysss: A lot of the Clojure books are available on Safari Books Online, if you're limited on budget and just want to get a feel they have a trial and are pretty reasonably priced otherwise.

Alex Miller (Clojure team)20:01:14

@shaun-mahood: hey, is Clojure Applied on there? I heard a rumor that was the case.

meow20:01:16

I heard Clojure Applied was a pretty good book 😼

jaen20:01:19

Well, if you know Clojure already though IIRC : V

bradford20:01:54

Heya. I'm looking for something like cond, but if test is true, I want to use the result of test in the expr. Does that make sense? I think as-> kinda gets me there...

jaen20:01:29

You want to take just one branch or chain the tests?

jcromartie20:01:36

you want "or"

jcromartie20:01:11

oh, never mind

jcromartie20:01:16

I understand what you're asking for

bradford20:01:47

@jaen: just one branch. I basically want the output of the test to be usable in the expr I execute

jaen20:01:17

Yeah, I kind of didn't notice the as before -> and wanted to suggest some->, but that's not it.

jaen20:01:42

So you basically want to have something like when-let but with multiple branches, like in cond. Not sure if there's something like that.

bradford20:01:26

Yeah, it'd look something like

(condb->
         (:pipelines a-graph) (prn "pipeline name:" %)
         (:graphs a-graph) (prn "graph name:" %)
	 (:sources a-graph) node) (prn  "source name:" %)
         )

jaen20:01:37

Hmm, there seems to be some cond-let s in utility libraries

bradford20:01:45

Yeah, that sounds like what I'd want

jaen20:01:26

For example

bradford20:01:41

Yeah, I was just looking at flatland.useful simple_smile perf!

jaen20:01:03

Oh, datascript has one too; useful to know

bradford20:01:22

I like how if I can think of the name of something, someone probably wrote it and it does what I expect. It's like, casting a magic spell or something.

jaen20:01:59

But you don't roll on casting ; d

jaen21:01:53

Sorry, I'm kinda that way : V

shaun-mahood21:01:27

@alexmiller: Clojure Applied is on Safari - https://www.safaribooksonline.com/library/view/clojure-applied/9781680501476/ From what I can tell, they have all the Clojure books from Pragmatic Bookshelf , O'Reilly books, Manning, and PacktPub books on there. They don't go on same day as they're published and you can't get access to the betas' but otherwise it's got a pretty complete Clojure library.

csmith21:01:49

Yeah, Clojure Applied is a very good book. I think its ~perfect as a second Clojure book

vanrysss21:01:00

very cool, thanks.

slester21:01:50

I actually just got Clojure Applied! It's moving a bit fast for me but I like it so far.

csmith21:01:11

slester, first chapter or so hits a bit harder than I’d maybe like but hang in there. I think it becomes worth it

Tim21:01:21

clojure applied is pretty good

Tim21:01:34

@slester: are you new to clojure?

csmith21:01:54

yeah, I wouldn’t recommend it as a first book

vanrysss21:01:16

Is Karin Meier's book any good for someone coming from Java/Go to Clojure?

slester21:01:56

@tmtwd: not super new, no. I did Advent of Code in Clojure and whatnot, but I'm progressing beyond toying with it and trying to write applications

Tim21:01:31

clojure for web development is coming

Tim21:01:36

I really want to read that

slester21:01:06

@csmith: it's just that I haven't seen some of this syntax before, like {:keys} 😞 I guess I might be too green for it.

csmith21:01:51

understood. Might be helpful to read a different book first or spend some time programming… I find {:keys } destructuring incredibly useful but it was very weird at first

csmith21:01:41

I usually have to spend some time solving problems and hitting certain walls before reading the right thing and having something really stick

slester21:01:13

Sure, but on the other hand I might not come across certain things just "programming" (not sure what that means even, tbh!)

slester21:01:42

So it's good in a way, since if I knew everything there'd be no point to the book

csmith21:01:45

yeah, that phrase wasn’t well formed. I meant building things to practice the language

slester21:01:20

I did have a question I haven't seen answered very well anywhere about structuring a project. I'm currently doing a game and I'm in circular dependency hell.

slester21:01:13

So I'm looking forward to chapter 6 for that reason, may just jump there now haha

slester21:01:39

still having trouble with circular dependencies though, flipping through I didn't really see anything that dealt with it

csmith21:01:49

haha. It is usually making namespaces smaller but the exact remedy isn’t always obvious

csmith21:01:01

err, often adding one namespace can fix it. if A and B depend on each other, like: A <-> B, then adding C and pulling some things out, making them both require C. that sort of thing

slester21:01:43

I may just have to do a rewrite to avoid going insane trying to figure out how to cut it cleanly. Thanks for the input @csmith! simple_smile

csmith21:01:52

hah sure np

kendall.buchanan22:01:04

Anyone know the correct way to take a function’s var (e.g. #’my-namespace/sample-job), convert it to text (`str` appears to do the trick), then back to a var again?

kendall.buchanan22:01:36

Essentially, I want to be able to store the function’s name, then recall it for evaluation later.

jcromartie22:01:49

I don't know how to get a clean symbol from a var. But you'll ultimately want to use symbols with ns-lookup to resolve the var again.

jcromartie22:01:16

I mean ns-resolve

jcromartie22:01:32

for example: (ns-resolve 'clojure.core 'map)

jcromartie22:01:43

returns the var #'clojure.core/map

kendall.buchanan22:01:03

You’re right – the var is one step away from being able to evaluate the function.

jcromartie22:01:17

well the var is good enough

jcromartie22:01:21

you can call a var

jcromartie22:01:47

(#'clojure.core/+ 1 2)

jcromartie22:01:56

(do we have a clojure bot here?)

jcromartie22:01:40

I remember in IRC I could do:

kendall.buchanan22:01:53

So the missing piece, then is taking a string and converting it to a symbol?

jcromartie22:01:37

I feel like parsing (str #'whatever) is a little bit iffy... should be a cleaner way

jcromartie22:01:25

metadata to the rescue

bradford22:01:28

I've got a simulation question for ya'll. I've built a distributed stream processing system, basically a DAG of queues and workers (powered by .jars). I'd like to simulate it on a single box. So I'm thinking of using that same DAG, but core.async = queues and Agents = workers. Is that the right way to think of this?

jcromartie22:01:16

@kendall.buchanan: the map returned by (meta some-var) has a :name key with a symbol, and a :ns key with the containing ns object itself

kendall.buchanan22:01:32

K, playing with it now...

jcromartie22:01:37

and you can call ns-name to get the ns symbol

jcromartie22:01:49

so, like: (-> #'map meta :ns ns-name)

jcromartie22:01:55

returns 'clojure.core

kendall.buchanan22:01:28

Are you suggesting this? (str (-> #'map meta :ns ns-name) “/" (-> #'map meta :name)) for the fully qualified string?

jcromartie22:01:53

where are you storing this?

kendall.buchanan22:01:10

It’ll be stored in Redis. My goal is to recall a function as a “job”.

kendall.buchanan22:01:18

That can be called elsewhere.

kendall.buchanan22:01:32

And I’d rather not use matching keys (if I don’t have to).

kendall.buchanan22:01:51

(Thanks for indulging this, by the way.)

jcromartie22:01:08

well, if it's making a round trip as a string, you might as well just use str or pr-str I guess

jcromartie22:01:55

I'd be concerned about the security implications of getting a var from a string and calling it

kendall.buchanan22:01:00

Okay, so I think I got it now: var -> str, then str -> symbol -> var.

jcromartie22:01:34

you can also round-trip a var with (-> a-var pr-str read-string eval)

jcromartie22:01:42

but, again, security...

jcromartie22:01:02

that's why I usually stick with namespaced keywords for job/command dispatch

jcromartie22:01:14

with a multimethod

jcromartie22:01:30

(defmethod do-job ::whatever [x] ...)

kendall.buchanan22:01:13

That’s actually a fine idea. Thanks.

kendall.buchanan22:01:20

Cool, thanks for all insights.

didibus22:01:14

Any way you can define a local global var?

didibus22:01:41

I basically want a Var that's shared between threads, but scoped locally to a function

jcromartie22:01:14

why would you use a var for that?

pguillebert22:01:30

java has a threadLocal concept

pguillebert22:01:08

but it usually goes against all clojure concepts simple_smile

didibus23:01:51

Well, I'm trying to test something, and I need to purposely create a synchronization bug

didibus23:01:37

I don't my declaring a global var, just thought it would be better I could avoid polluting the namespace with it

didibus23:01:43

don't mind*

juhoteperi23:01:44

@alexmiller: By the way, when are 2015 State of Clojure Community survey results coming?

andrewboltachev23:01:04

Hi. Is there a way to pretty-print into a string w/o hacks like capturing output?

bfabry23:01:56

@andrewboltachev: pprint takes an optional writer argument, so a StringWriter in there would work. imo capturing output is simpler

bfabry23:01:38

(with-out-str (clojure.pprint/pprint foo)) vs (let [sw (StringWriter.)] (clojure.pprint/pprint foo sw) (.toString sw))

andrewboltachev23:01:56

yeah, didin't know about with-out-str simple_smile

stopa23:01:33

hey everyone, I am using aleph and manifold. when I make a post request ->

(-> (aleph.http/post url opts)
    (manifold.deferred/on-realized cb cb))
the request ends up getting sent twice. but, if I instead write
(-> (aleph.http/post url opts)
    (manifold.deffered/chain cb)
    (mainfold.deffered/catch cb))
It works fine. : | My question is, what could be the different between (d/chain) and (d/on-realized), that could cause the request itself to send twice?

bfabry23:01:44

ok cool glad I could help, very useful little macro

meow23:01:10

@juhoteperi: Last I heard Alex say he had written up the survey results and someone is editing that report - should be soon.

didibus23:01:00

I don't know why I didn't think of it, but a local atom used with reset is basically a mutable variable shared across thread. So it's essentially similar to a global root var.

jonahbenton23:01:29

@didibus: well, you'd still have to ensure the same atom is used across threads. a true local, e.g. created in a function-local let, would be created anew on each function invocation. an atom captured in a closure, though, would be a shared mutable.

didibus23:01:50

@jonahbenton: ya, that's true, in my case, that's exactly what I wanted, for the state to be reset when I call the function again

anisoptera23:01:04

not that i'm actually planning on using this in any meaningful way, but is there a way to go from a "compiled" anonymous function object back to the s-expressions used to create it?

anisoptera23:01:47

or is it compiled to jvm bytecode and then the actual list discarded?

dmitrig0123:01:45

quick question - I have a clojure project that provides an http server, but as part of that project I've also written some scripts that do db schema migrations and such (on postgres). right now I'm just triggering those scripts by executing them in lein repl, but it would be great if I could make some kind of standalone command (either as part of lein or even outside of it) that would run those. how might I go about doing that?

dmitrig0123:01:21

like, some super simple way to hook up lein run-schema-migrations to call a certain function