Fork me on GitHub
#clojure
<
2017-04-21
>
lvh02:04:53

delay does the Right Thing when deref’d from multiple threads, right? Computation will happen at most once?

lvh02:04:05

@tbaldridge by the way thanks for the diffing hints

ghadi02:04:17

delay is guaranteed once

raspasov03:04:13

everyone: has anyone tried/considered or seen something that utilizes clojure.spec to generate SQL (and more specifically SQL joins)?

raspasov03:04:56

(that sounds as scary as an ORM 😄 ) but I believe it can of a very good (clojure.spec) kind haha

raspasov03:04:41

the way I imagine it: let’s say you have a table called “products” and a table called “images”, I want to get all products with all their images joined; I can have a clojure.spec for a “product” and for an “image” and a spec that describes how they link together; from that generating something like a HoneySQL clojure map can be pretty straightforward I think

raspasov03:04:22

pros: no need to write a lot of manual SQL…

raspasov03:04:56

cons: it can be a leaky abstraction depending on how it’s done (I haven’t thought much about it)

raspasov03:04:43

let me know if you think this is a good idea and and even better why it might NOT BE a good idea 🙂

didibus03:04:29

@cddr I disagree with the advice to avoid with-redefs. There's nothing wrong with it. It rebinds the root from the moment you enter its s-expression, to the moment you leave it. There's no issue with threads either, since it does so atomically. What @tbaldridge is talking about are just some caveats you need to be aware of, not actual issues with the function. For example, because the root is restored when you leave the s-expression, if you have a thread still trying to access it after you've left, it will now get the old binding back. Similarly, if you have a lazy sequence, which will try to realize itself after you have left, it will get the old binding too. This is normal, since it restores the old binding once you leave the s-expression.

didibus03:04:04

I personally agree with Rich's advice, design should not be a consequence of wanting to make testing easy. With-redefs does come in handy to test things, and changing the design of the code to avoid using with-redefs is not always the right thing to do.

didibus03:04:24

Now, if all your tests must use with-redefs, chances are you made some wrong choices, but if you know the trade offs, and believe your design is good, I don't see any issue using with-redefs, and I'd say that's better then forcing a change in your design for testing only

tbaldridge03:04:43

@didibus nah, avoid with-redefs because it's good design. Avoiding uncoordinated global mutation is good design. That's what clojure is all about right? Immutable data, pure functions? Why do we throw all that away at testing time?

didibus03:04:15

In your production code yea, but in your tests I don't see any issue with it.

didibus03:04:49

There are also good reason to alter var roots in prod, like for AOP style programming.

didibus03:04:05

But yes, you must know what you are doing

didibus04:04:05

I'd trade simplicity in my production code, over complexity in my test code

tbaldridge04:04:18

But above all that with-redefs encourages testing the wrong thing.

tbaldridge04:04:51

Let me give you an example: with with-redefs I may say: "Make sure foo is called with 42 as an argument". That's not testing what matters. Why do I care if foo is called? In reality I'm subbing foo because it's side-effecting. In which case what I really care about is that I'm creating the correct side-effect. So I really should be testing that, and not the fact that bar called foo.

tbaldridge04:04:11

On top of all that, if foo is really side effecting, why is it buried so deep in my app that it's hard to swap out via means other that var redefinition? That's another design problem: side-effecting deep in the call-stack.

tbaldridge04:04:01

But really, I've been programming Clojure for many years, I've written compilers, I've written crazy macros and DSLs. And I can't get with-redefs right every time. How can I expect a mid-level developer or even a junior-level get it right?

tbaldridge04:04:19

And I'll stop ranting now 🙂

didibus04:04:50

@tbaldridge Well, I agree with you on those. You should probably just have an integration test for that side-effect. And you shouldn't side effects deep in the call stack. But, if for some reasons you do, and you can't get rid of it because of time constraints, opportunity cost, or it really makes some other things easier, why not still unit test it with the help of good old with-redefs?

didibus04:04:11

The cost of getting with-redefs wrong in a test isn't that high though. Your unit tests just fails.

tbaldridge04:04:25

And then you stare at it for a hour or two, as does the next guy who has to maintain your tests...

tbaldridge04:04:40

That's really what got to me over time, I'd start working on a project for a client, make a small modification, and all the tests would break. Or worse they wouldn't break. That's probably the most common problem. I'd modify a function, run all the tests and everything passes! Since the code I modified was all mocked out via with-redefs

didibus04:04:11

@tbaldridge Hum, you're slowly changing my mind 😛 I might have to revisit a co-worker's code review now

didibus04:04:14

Hum, still feel like with-redefs might be best in his case.

didibus04:04:24

Its a case where the app is a simple ETL job. It works using this model where there's a pipeline of steps which take data and meta and transform them, and return the transformed data and meta. The meta is used by later transform steps to give details based on the previous steps that can help them decide how to do their transformation. Now, some of the steps have side-effects, like logging, and pumping out audit info, metrics, etc.

tbaldridge04:04:48

Could be, I don't recommend refactoring a ton of namespaces just to get rid of one with-redef.

didibus04:04:52

Well, its the case where most steps don't have side effects, and injecting and carrying all these states throughout the transformation steps would feel just like an annoyance, each of the side effecting steps might need a slightly different metric state, etc. So its like a small convenience evil, and to mock those with-redefs comes in handy

didibus04:04:23

But, I do see your points, probably most of the time avoiding with-redef is best.

didibus04:04:49

I'll think more about it if I see it used again that's for sure.

didibus04:04:57

@tbaldridge Oh, BTW, kind of a parenthesis question. I've read your blog post. I was wondering if you know why Vars were made ThreadLocal? I couldn't figure out a scenario where it is useful

tbaldridge04:04:56

That's how bindings work, with thread-local:

`(binding [*out* some-stream]
   ....)

didibus04:04:59

I know, but why ThreadLocal? I mean, it doesn't seem like its needed for the implementation. The stack frames were enough to give the dynamic extent no? Why wrap them in a ThreadLocal?

tbaldridge04:04:51

Because otherwise one thread's call to binding would clobber another thread's.

didibus04:04:53

I kind of get it conceptually, but I was trying to find out an example of when that would happen and I couldn't

tbaldridge04:04:34

call that from two threads at once without thread-local bindings, and you'll get corrupted text

didibus04:04:02

Oh, that's a great example. Ok, thanks.

didibus04:04:24

I'll use it in a blog post I'm writing if you don't mind?

curlyfry08:04:24

Just created #integrant for discussing https://github.com/weavejester/integrant

qqq08:04:20

how do I write @font-face in css garden ?

cgrand08:04:37

Hey fellow clojurians! Could you try this in your repl? (Clojure 1.9) and reports the repl and if it managed to evaluate it or not:

#:#_()#! bang bang
#?(:whatever 42); now a blank line

#?@(:default ())foo
{:bar :baz}

sveri09:04:37

I am not sure what you want to achieve exactly. Typing #:#_()#! bang bangin my REPL gives me a RuntimeException EOF while reading

sveri09:04:13

This is 1.9.0-alpha14 btw.

nha09:04:34

user> #:#_()#! bang bang
RuntimeException Reader tag must be a symbol  clojure.lang.LispReader$CtorReader.invoke (LispReader.java:1221)
()
user> #?(:whatever 42); now a blank line
user> #?@(:default ())foo
RuntimeException Reader conditional splicing not allowed at the top level.  clojure.lang.Util.runtimeException (Util.java:221)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(*cider-repl localhost*:1:7821) 
user> {:bar :baz}
{:bar :baz}
user> *clojure-version*
{:major 1, :minor 7, :incremental 0, :qualifier nil}

lincpa10:04:20

it's not exec and do nothing in repl of nightcode (clojure 1.9 alpha 14).

noisesmith14:04:35

#foo{:bar :baz} in my vanilla repl (clojure.jar + rlwrap)

noisesmith14:04:06

in a lein repl using 1.9 alpha14 the blank line is fine, and I get a conditional splicing not allowed at top level error, and unable to resolve symbol: foo, and then {:bar :baz} as a non-namespaced map

noisesmith14:04:26

same clojure version, so nrepl must be broken for these reader changes

noisesmith14:04:26

(using REPL-y 0.3.7, nrepl 0.2.12)

cgrand15:04:30

Thanks all, so nothing but vanilla repl seems to work

ben.mumford10:04:18

is anyone here familiar with the elastisch library?

mccraigmccraig10:04:24

i've used it in the past @ben.mumford , not so much recently because it doesn't support async

ben.mumford11:04:37

good man, any idea how to get it to connect to an elasticsearch cluster?

ben.mumford11:04:09

the connect method only takes a single url (unlike the official java rest client)

ben.mumford11:04:20

what happens if the server is down?

ben.mumford11:04:28

any help greatly appreciated

mpenet11:04:06

@ben.mumford spandex (a lib I maintain) handles failover etc

mpenet11:04:20

and does cluster node discovery out of the box

ben.mumford11:04:14

i tried that but when i use it in my application (simple ring stuff) the number of file descriptors my application uses keeps climbing

ben.mumford11:04:43

i chose spandex initially specifically for that reason

mpenet11:04:20

you got a fd leak with spandex? doesn't sound normal, are you re-using the "client" instance or creating one per request maybe?

ben.mumford11:04:39

i created the client once and reused it

ben.mumford11:04:55

my application takes requests and proxies through the elasticsearch

mpenet11:04:48

We've been using it for quite some time on some heavy stuff and never had any leak, I am curious on what's happening here

mpenet11:04:25

if you can share some code I could have a look

ben.mumford11:04:04

eg: (def ^:private client (spandex/client {:hosts [es-cluster-url]})) (defn ^:private read-docs [client index type {:strs [query from size] :or {query "*" from 0 size 10}}] (let [response (spandex/request client {:url (spandex-utils/url [index type "_search"]) :method :get :body (create-query from size query)}) hits (->> response :body :hits :hits)] (timbre/info "Query:" query "From:" from "Size:" size ". Found:" (count hits) "matches.") (map map-hit-to-doc hits)))

qqq11:04:12

how do I use cljsjs.opentype ?

qqq11:04:22

when I try to require it, I get an err of cljsjs can't be found

ben.mumford11:04:28

the read-docs method is then called from one of the endpoints in the app context

mccraigmccraig11:04:25

@ben.mumford i don't really have the failover problem because of the way i deploy ES - i deploy a proxy (nodata) instance on every host, which then manages forwarding to a live ES data instance

mccraigmccraig11:04:05

i suppose it's possible for a nodata instance to die, but it's not happened in the last 5 years, which is more than i can say for the data instances

ben.mumford11:04:21

having spoken with @mpenet offline, we believe the problem was me bungling it creating multiple clients accidentally (not the spandex library). incidentally, despite my ineptitude the library has been very easy to use and is highly recommended

mpenet11:04:12

@mccraigmccraig we used to do it this way too, it's a good approach too. Spandex does sniffing and detects new/dead nodes and does penalisation if too many failures etc etc, one advantage is that you don't have to worry about compatibility among other things (it just uses rest)

mpenet11:04:16

there's a perf hit tho, but it's very minimal

mccraigmccraig11:04:26

i was going to look at spandex... we are currently using a hacked version of qbits.esearch

mpenet11:04:02

yeah esearch was very naive/simplistic

mccraigmccraig11:04:29

right - was very easy to replace the http client with our own

mpenet11:04:42

spandex follows more or less the same design as alia, I guess you might like it 🙂

mpenet11:04:05

(well no manifold module, but it's easy to add)

mccraigmccraig11:04:23

cool, i'll check it out - when the customers stop demanding new features 🙂

micahasmith13:04:26

(defn my-func [opts]
  (assoc opts :something :else))

(let [fqn (resolve 'my-func)]
  ;; how to use fqn to get func and call it?
  (fqn {:hello :world}))

john13:04:54

Pretty sure I got bit by this on CLJS while using web workers. with-out-str was capturing other printlns.

micahasmith13:04:48

oh wait, that just works

micahasmith13:04:20

hmm. so i’m trying to serialize functions names to strings, and then unserialize them to call them

mbjarland13:04:59

granted I'm still wearing my training wheels with clojure, but just discovered a new friend - cl-format. For kicks and giggles, added the following snippet to rosetta code as a clojure solution to the word wrap problem:

(defn wrap-line [size text]
  (clojure.pprint/cl-format nil (str "~{~<~%~1," size ":;~A~> ~}") (clojure.string/split text #" ")))
cl-format...some serious lisp-fu there...and a throwback to...I don't know, the 70's?

mbjarland14:04:22

clojure -> common lisp -> lisp machine -> multics...and still kicking (edit and apparently -> BOS)

mikerod14:04:42

Posted in leiningen, but haven’t seen much activity there and figured this may be relevant here too (before making the post on stackoverflow or something): I have a lein project.clj with a repo in :repositories configured with :creds :gpg. I have an GPG encrypted credentials.clj.gpg file stored under my ~/.lein profiles dir. This works. The problem I have is that I’m being prompted in the terminal for my GPG passphrase every time Leiningen needs to access this file, e.g. lein deps, lein install, lein repl, etc. I have tried setting up an gpg agent daemon via eval "$(gpg-agent --daemon)", but I am still having Leiningen repeatedly request for my passphrase. I have looked online, but haven’t been able to find an answer. Any suggestions from anyone here?

joost-diepenmaat15:04:00

@mikerod I have the following magic stuff in my .profile

joost-diepenmaat15:04:58

also note that you may or may not need a :signing {:gpg-key ""} entry in your project/profile

joost-diepenmaat15:04:44

the export GPG_TTY=$(tty) is necessary for me on OSX.

mikerod15:04:26

I’ve heard of the GPG_TTY part and have that (I actually never really understood why it was needed). I’m on OSX too.

mikerod15:04:40

Thanks for those details though. I’ll give the rest of it a try. it is a bit different than what I’ve done

mikerod15:04:56

quite a bit of hackery involved here 😛

mikerod15:04:06

I just find the repeated spamming for my passphrase to be not-so-fun

joost-diepenmaat15:04:12

good luck. I get desparate every time it breaks 🙂

lvh16:04:53

When you put a dependency in a toplevel :dependencies clause of a leiningen project.clj, what profile does it really go into? Context: I’m trying to have a project with a shared codebase where I can still have separate ubjerjars for different components that only have the deps they need.

tanzoniteblack16:04:27

You should take a look at https://github.com/zcaudate-archive/lein-repack which is a lein plugin that attempts to automatically solve this problem

lvh16:04:39

cool, thanks!

jsdiaz1917:04:46

I downloaded a project in clojure and I want to run it. I go to the directory and run the lein run command but I get the error "no. Main main namespace specified in project.clj."

jsdiaz1917:04:51

can anybody help me?

weavejester17:04:45

@jsdiaz19 maybe the project isn’t runnable. Perhaps it’s a library?

weavejester17:04:09

What project is it?

bansari.desai17:04:31

@jsdiaz19 I think you need to define main in project.clj

bansari.desai17:04:29

I took this screenshot from project -->lein new app myapp

weavejester17:04:07

@jsdiaz19 there’s no :main namespace stipulated in the project file, and nothing in the README about executing it. Maybe it’s unfinished?

jsdiaz1917:04:47

thank you very much. Then how could I do a multiplayer game with sockets in clojure?

qqq17:04:10

I'm sure I've asked this before here.

qqq17:04:17

I have an integer (ascii code). I want to convert it to a char.

qqq17:04:19

How do I do that?

tanzoniteblack17:04:12

(char 80) --> \P

qqq17:04:17

I was searching for chr and asc

qqq17:04:07

one mpore dumb question: how do I do string -> int without calling "read-string" ? or should I just call read-string?

tanzoniteblack17:04:37

(Integer. my-str)

tanzoniteblack17:04:42

will throw an error if it's not an int

harkonnen17:04:34

Quick question, is there an article that explains a good workflow and tools for Clojure? I use Intellij and Cursive

tbaldridge17:04:41

@qqq Long/parseLong

nyor.tr19:04:06

I'm trying out the new version of duct https://github.com/duct-framework/duct (0.9.0-alpha2) and I would like to know if it has support for figwheel. If so, how can I start the figwheel server?

curlyfry08:04:35

If you generate the project with +cljs a figwheel server will be included (through https://github.com/duct-framework/module.cljs). Check out the README in your generated project for instructions on how to start it.

curlyfry08:04:09

Seems like it's configured to only reload files in the browser when you call (reset) in the repl

nyor.tr07:04:20

Thanks, So there is no "watch files" option that will reload when a file changes?

curlyfry13:04:18

Not that I know of, but all that I know about it is from the README :)

foobar19:04:37

I am trying to read some clojure dumped with (binding [print-dup true] (prn data-structure)) When I try to read it, it complains that it cannot find a matching method create. The dumped code has entries like so: #=(datomic.query.EntityMap/create [#=(clojure.lang.MapEntry/create

foobar19:04:48

Try lein trampoline run -m clojure.main figwheel.clj (where figwheel.clj has the contents above

lassik21:04:52

Hello. Are strings returned by (name :some-keyword) somehow different from ordinary literal strings? We're have a Java/JNI API that crashes on the former but accepts the latter.

Alex Miller (Clojure team)21:04:21

no, they are just normal Java strings

hiredman21:04:16

the reader interns literal strings, and I thought the keyword and symbol creating functions end up intern strings too, but I don't see where

hiredman21:04:09

maybe your jni code has issues with strings that aren't interned

Alex Miller (Clojure team)21:04:40

neither of those things is true

Alex Miller (Clojure team)21:04:30

the compiler will store string literals in the constant pool of the compiled class which has the effect of interning them I think, but the reader does not explicitly call intern on strings afaik

lassik21:04:49

And now comes the inevitable moment where I slap myself on the forehead 😄 (defn my-utility-function [name] ... (name name)) Lisp-2 background...

Alex Miller (Clojure team)21:04:09

symbols (and keywords, which use symbols) used to intern, but we found that had a significant performance cost

hiredman21:04:05

huh, and the reader doesn't intern strings either, I wonder how I ended up thinking it did