Fork me on GitHub
#clojure
<
2018-10-24
>
bringe01:10:51

Has anyone ever seen an error when using with-redefs like:

clojure.core$constantly$fn__4614 cannot be cast to clojure.lang.IFn$OLO
?

noisesmith17:10:26

that function signature means the original function was type hinted to allow unboxed args (iirc that specific signature is "returns Object, takes Long and Object as args"), and that means that code that is compiled to use it targets that interface of IFn and not the generic interface constantly implements

noisesmith17:10:37

you could try (fn [^Long _ _]) as a replacement for (constantly nil), as it should implement that same interface

noisesmith17:10:52

and here's an anonymous function that has that signature and returns nil

user=> (supers (class (fn [_ ^long _])))
#{java.io.Serializable clojure.lang.IObj java.lang.Object java.util.Comparator clojure.lang.AFn clojure.lang.IFn clojure.lang.IFn$OLO clojure.lang.AFunction java.util.concurrent.Callable clojure.lang.IMeta clojure.lang.Fn java.lang.Runnable}

noisesmith17:10:11

so use (fn [_ ^long _])

bringe01:10:21

I'm getting it only when trying to redefine a particular third party function, but all my other redefs work fine. I've created a simple example to demonstrate/isolate outside the context of my actual code. This also throws the error.

(defn testing-redef
  []
  (langohr.confirm/wait-for-confirms-or-die "channel" 100))
(deftest redef-test
  (with-redefs [langohr.confirm/wait-for-confirms-or-die (constantly nil)]
    (is (= nil (testing-redef)))))

bringe01:10:58

I am doing the same thing with other functions from the same library and it works fine.

seancorfield06:10:39

This article inspired me to try something out with tap> (in Clojure 1.10): https://quanttype.net/posts/2018-10-18-how-i-use-tap.html -- I started a REPL and provided the JVM options to also start a Socket REPL then I connected to the REPL with my editor and I connected to the Socket REPL with nc. In the Socket REPL, I typed (add-tap (bound-fn* clojure.pprint/pprint)) and then continued to work in my editor, adding calls to tap> as needed (or (doto tap>) in -> threads), and seeing the pretty-printed values stream out of the nc-connected terminal session without interrupting my input/output and logging etc in my editor-connected REPL. Very nice!

8
8
👍 12
4
tristefigure07:10:29

Is it possible to use tap> with the emitter and receiver end in the same thread/repl in order to collect and delay the printing of debug statements ?

seancorfield14:10:07

Yes. That's how I tried it first, when it first dropped. I like this method better tho' with multiple REPLs keeping all the interactions separate.

danp08:10:25

Hi all, I'm calling some Clojure (1.8) code in a larger Java project that I don't entirely have control over. Recently some code has been to the parent that's causing conflicts with clj-http. Is there a way I can ignore conflicts originating outside of my Clojure code, in lein or otherwise?

schmee08:10:53

if you’re requiring the Java project as a jar, you can use :exclusions in lein to exclude deps in the same way as maven: https://github.com/technomancy/leiningen/blob/master/sample.project.clj#L55-L59

danp08:10:13

Sorry I wasn't clear, there is a parent java project - my Clojure jar and a separate Java jar are both children to this parent. The recent inclusion of the child Java jar has resulted in the dependency conflict.

kirill.salykin08:10:52

hi all, is it possible to invoke passed via thread macro?

(defn hi [name] (prn :hi))
(defn hello [name] (prn :hello))
(def greets {:hi hi :hello hello})
(-> greets :hi #(% "Kirill"))

kirill.salykin09:10:40

(example of course doesnt work

schmee09:10:28

yes! 🙂 (-> greets :hi (#(% "Kirill")))

schmee09:10:13

you can use (macroexpand '(-> greets :hi #(% "Kirill"))) to see why one works and the other one doesn’t

kirill.salykin09:10:22

that explaing weird message about keyword

Bravi09:10:19

hi everyone. even though there’s a reagent component in this question example, it’s more of a clojure question so I think it qualifies for this channel 😄 so I had this

(defn some-component [is-active?]
  [:div {:style {:opacity   (if is-active? 1 0)
                 :width     (if is-active? "100%" "20%")
                 :height    (if is-active? "100%" "50%")
                 :font-size (if is-active? 14 10)}}])
and to reduce the amount of ifs, I created this
(defn some-component [is-active?]
  [:div {:style (css-props is-active?
                            :opacity   1 0
                            :width     "100%" "20%"
                            :height    "100%" "50%"
                            :font-size 14 10)}])
and the function looks like this
(defn css-props [condition & forms]
  (let [parts        (partition 3 forms)
        transform-fn (fn [[prop truthy falsey]]
                       [prop (if condition truthy falsey)])]
    (->> parts (map transform-fn) (into {}))))
I was just wondering perhaps there’s a better / built-in way to do something like this?

Jan K09:10:00

@bravilogy in this case i'd define active and inactive style maps separately and choose between those with one if.

ClojureNoob09:10:16

Hi all, I'm new here. I've joined because I've gotten stuck on a problem and can't figure it out, was wondering if anyone could give pointers?

ClojureNoob09:10:24

(some background):

ClojureNoob09:10:01

after getting excited about Clojure, I've "deep dived" and rewrote a small web app (which is in production)

ClojureNoob09:10:24

I've ported about 99% but have now hit a brick wall 😞

ClojureNoob09:10:44

I understand this is probably not the best way to learn Clojure, so its likely I'm doing falling over something very basic

thheller09:10:33

its absolutely the best way to learn Clojure. I did it that way. 😉

ClojureNoob09:10:11

everything else has worked up to this point

Bravi09:10:22

same here

Bravi09:10:05

but I tackled quite a big project straight away 😄 got stuck loads of times, but the Clojure community was super helpful every time

ClojureNoob09:10:25

the error I get is this:

ClojureNoob09:10:28

clojure.lang.LazySeq cannot be cast to clojure.lang.IFn

ClojureNoob09:10:03

and all I'm doing is passing a hash map into a function 😐

Bravi09:10:31

you should post the code snippet that throws this error. looks like you’re trying to call a list (I think)

ClojureNoob09:10:14

that's strange

ClojureNoob09:10:34

this is how I construct the hash map:

ClojureNoob09:10:08

that code block works perfect

ClojureNoob09:10:44

the issue is when I call this in another function like so:

Bravi09:10:05

(do (save-email data db) ;; <----- PUT do IN HERE
       (generate-string {:status "ok" :data email}))

👍 12
thheller09:10:27

the nested def is bad. move it into (let [data (unwrap...) email (...)] instead

👍 8
ClojureNoob09:10:03

yeah, sorry I had that inside a let, but I then moved into def when I hitting my head against a wall

ClojureNoob09:10:09

and trying different things

thheller09:10:43

yeah if you do ((save-email data db) (generate...)) you are calling the return value of (save-email...) as a function

thheller10:10:06

do is what you want there for running both after each other

ClojureNoob10:10:29

ok I'm doing to try that right now, one sec

Bravi10:10:30

another thing I’d change - instead of (header "user-agent"), I’d put ("user-agent" header). because if for any reason you get anything other than map in header, that will throw an error as well

😊 4
Bravi10:10:51

same for form

thheller10:10:09

that doesn't work

thheller10:10:11

strings are not callable

Bravi10:10:26

ah right, then use get I guess

thheller10:10:33

(get header "user-agent") is nil safe

ClojureNoob10:10:45

honestly I'm really happy, I spent far too long on this final bit!

ClojureNoob10:10:30

yeah I had (get foo :key)

ClojureNoob10:10:44

then I read somewhere its the same as (foo :key)

thheller10:10:09

it is the same unless foo is nil

Bravi10:10:11

that’s because maps can be used as functions and so can keywords

thheller10:10:14

(nil :key) will break

ClojureNoob10:10:26

ah, ok yes that makes sense, because that shortcut assumes foo is a map?

thheller10:10:36

(:key nil) is fine as well as (get nil :key)

jaawerth10:10:46

if there's no legitimate usage where you'd pass a non-map for header, I'd still use it though. You can always fall back to an empty map on nil

ClojureNoob10:10:48

so I'm guessing (get foo :key) is safer?

thheller10:10:10

for keywords it is "standard" to use the reverse (:key foo) short form

jaawerth10:10:14

but yeah either way. I just like code to yell at me sooner rather than later for these things

thheller10:10:19

just can't do that for strings

ClojureNoob10:10:52

so, this do function does this force evaluation?

thheller10:10:27

it does not force lazy seqs no

ClojureNoob10:10:31

I'm just trying to understand the solution 🙂

jaawerth10:10:59

do is a special form. it just evaluates expressions in order and returns the value of the final one - see (doc do) from the repl 😉

ClojureNoob10:10:14

ok perfect I'll look that up

ClojureNoob10:10:53

can't thank you guys enough, this blocker was driving me nuts

ClojureNoob10:10:13

the next steps will be a burn out trial, with this new Clojure on a test server 🙂

ClojureNoob10:10:26

if it works fine for a couple of works

ClojureNoob10:10:39

I'll probably replace our prod version 😄

Bravi10:10:39

p.s. you could also do destructuring like this

(defn unwrap-unsub [req]
  (let [{ip                    :remote-addr
         {agent "user-agent"}  :headers
         {email    "email"
          campaign "campaign"} :form-params} req]
    {:email email :ip ip :agent agent :campaign campaign}))

ClojureNoob10:10:07

that's even more cleaner

ClojureNoob10:10:36

slight tangent question, do any of guys have Clojure in production and if so, any tips/advice?

jaawerth10:10:13

I'm slow-rolling it (nobody else on my team knows the language.. yet and I'm paranoid about writing code that only I can maintain... generally comes back to bite me at inopportune times) so not quite yet. Soon though!

ClojureNoob10:10:53

fair enough, I have interest from 2 other devs, and we almost free choice to use any language

jaawerth10:10:02

others here do, though

jaawerth10:10:31

I think it's worthwhile, particularly if you have to do any jvm stuff

ClojureNoob10:10:49

well the JVM is another story 🙂

jaawerth10:10:27

that's my angle on getting it at work - we're gonna have to write extensions for a java platform soon and we will turn into a java shop over my dead body

ClojureNoob10:10:07

while our group has literally almost every language, the JVM hate is strong 😞

ClojureNoob10:10:17

we have everything from C# to Haskell going on

ClojureNoob10:10:36

and I've added Crystal in there as well 😂

jaawerth10:10:53

JVM has its benefits, the java is the painful part IMO. But hey, there's always ClojureCLR if you do C# stuff! Not as much of a community though

ClojureNoob10:10:21

I did start off on C# many moons ago

ClojureNoob10:10:31

and .net core is ok kind of

ClojureNoob10:10:49

I actually like the JVM, its the rest of the team

thheller10:10:54

JVM hate is usually FUD from people that equate the JVM with Java

ClojureNoob10:10:32

yeah, I think that's exactly the issue, as soon as the JVM is mentioned, door is closed

ClojureNoob10:10:32

devs think "JVM = Java"

ClojureNoob10:10:48

oh yeah, we even have production Scala

jaawerth10:10:40

oh, well then you've already broken the jvm seal

ClojureNoob10:10:57

yeah, also, everyone love Metabase which just rocks

ClojureNoob10:10:16

those are 2 production systems already using JVM

ClojureNoob10:10:40

and also, don't hate me, but I was porting some of our legacy apps to Kotlin

jaawerth10:10:55

I don't think there's any particular kotlin hate here, lol

ClojureNoob10:10:10

personally I use different languages depending on the project

ClojureNoob10:10:11

of all the languages I've used so far, Clojure has really sparked my interest (and Crystal did that for a bit too)

ClojureNoob10:10:08

its ticked every feature I've wanted

ClojureNoob10:10:42

the only thing, which would be super super awesome is getting GraalVM native imagine to work, which thus far I've not got to work

ClojureNoob10:10:04

in fact I don't think I've every got GraalVMs native to work on any project 😐

ClojureNoob10:10:45

but then again, I can put the uberjar into a docker container, so not the end of the world

jaawerth10:10:09

GraalVM still needs time to cook

ClojureNoob10:10:27

yeah, but I'm just so impatient 😄

ClojureNoob10:10:06

I did look into Avian, which is like 2.2mb JVM, some people where bundling their jars with it to make a single executable

ClojureNoob10:10:43

but the steps looked to hairy for me

ClojureNoob10:10:52

😏 I was hoping there was some lein plugin the lazy me could just do $ lein build avian

dpsutton17:10:46

i changed some :main-opts to a different profile and they still seem to be invoked. do i need to manually clear the .cpcache? i see there are caches of the main in there as well

jrychter17:10:10

Short of writing a custom macro, is there an idiom for composing transducers where some stages are optional (e.g. could be disabled)? Sort of like cond->>. What I'm doing right now is building a list of transducers manually and then applying comp to it, but I wonder if there is another way?

schmee17:10:21

not AFAIK. rolling your own macro is perfectly fine for this 🙂

hiredman17:10:52

you don't need a macro for it

hiredman17:10:57

you are writing a function A that takes a function B and returns a function C. C conditionally applies B to is inputs

jrychter17:10:01

The decision on whether a transducer is to be applied is static, e.g. I don't want to branch on every data item. And I think I'll stick with the current solution (build a vector using cond->, then apply comp to it)

noisesmith17:10:38

you could also use filter to produce the list of transducers

dpsutton17:10:34

(defn xf [{:keys [e? o?]}]
  (comp
   (if e? (filter even?) identity)
   (if o? (filter odd?) identity)))

dpsutton17:10:50

you just just compose with identity or the thing, right?

dpsutton17:10:58

(into [] (xf {:e? true}) (range 10))

jrychter18:10:13

Yes, well, I wanted to avoid the superfluous identity calls.

awb9918:10:07

I have a strange behavior with "lein ring server" for subscribe-topics-of-interest-demo. When I run this function in the repl, it runs through each entry in the map as it should. But when I run the same function via "lein ring server" then it only prints "subscribing to 5 topics of interest", and then does not execute the map. Any ideas why this happens?

schmee18:10:37

the problem is map is lazy. in the repl, lazy collections are forced automatically, but in regular code they’re not

schmee18:10:52

try replacing map with run!

awb9918:10:39

@smeee @noisesmith Thanks! run! works perfectly.

isak19:10:12

is there a way to pass parameters by name rather than position with jdbc?

noisesmith19:10:44

there are definitely libs that use jdbc and allow providing params by key - eg. hugsql https://github.com/layerware/hugsql

noisesmith19:10:16

hugsql turns sql files into clojure functions that you use with jdbc, and the parameters in the file become keys

isak19:10:51

ah, in my case queries need to be generated at runtime, so may not be a good fit

noisesmith19:10:04

oh, that's much trickier yeah

noisesmith19:10:17

there's other dsls though

isak19:10:42

i'm surprised people are hiding this feature, in .NET everyone passes params by name

noisesmith19:10:45

clojure.java.jdbc recommends honeysql

isak19:10:24

i don't think I can do DSLs either, unless they are really on top of advanced sql server features (probably not)

noisesmith19:10:02

well, anything that provides the ability to do params by key would be a dsl, clojure.java.jdbc doesn't do that directly

noisesmith19:10:41

(as far as I know at least)

isak19:10:16

strange, in .NET everyone does this (or uses something that does):

using(var conn = new SqlConnection("..."))
    using (var cmd = conn.CreateCommand()) {
        cmd.CommandText = "select top 10 * from foo where bar = @myParam";
        cmd.Parameters.AddWithValue("myParam", 1);
        var rdr = cmd.ExecuteReader();
        ...
    }

isak19:10:48

the CommandText you see there is also what shows up in all the logs verbatim, so I don't think there is any runtime magic going on to translate it

tavistock19:10:20

it looks lik jdbc (as of ’10 https://stackoverflow.com/questions/2309970/named-parameters-in-jdbc) doesn’t support named args

4
tavistock19:10:54

and their suggestions are basically use a dsl

seancorfield19:10:44

Yeah, I've looked at supporting named parameters directly in clojure.java.jdbc but ran into that... and I mostly point people at HoneySQL which supports named parameters as an abstraction on top of clojure.java.jdbc.

seancorfield19:10:32

@isak There's a #sql channel if we want to dig deep on that and avoid cluttering up this main channel. It's surprising to me how few Clojurians overall seem to use SQL DBs 🙂

isak19:10:59

good to know, thanks guys

seancorfield19:10:35

HoneySQL lets you drop pieces of raw SQL into the DSL so, depending on what you need, it may get you close enough.

4
seancorfield19:10:33

(! 848)-> clj -Sdeps '{:deps {honeysql {:mvn/version "RELEASE"}}}'
Clojure 1.9.0
user=> (require '[honeysql.core :as h] '[honeysql.helpers :refer :all] '[honeysql.types :refer :all])
WARNING: update already refers to: #'clojure.core/update in namespace: user, being replaced by: #'honeysql.helpers/update
nil
user=> (-> (select #sql/raw "top 10 *") (from :foo) (where [:= :bar #sql/param :my-param]) (h/format {:my-param 42}))
["SELECT top 10 * FROM foo WHERE bar = ?" 42]
user=> 
like this @isak

seancorfield19:10:35

We use HoneySQL heavily at work because we build queries on the fly and need the composability it offers.

isak19:10:07

Just checked, and the jdbc queries get translated to use SQL parameters for SQL Server. So I guess the current situation is people are writing DSLs to convert from readable forms to forms understandable by jdbc, that will then get converted back to the original form 🙂

isak19:10:37

@seancorfield cool, i'll check that out

seancorfield19:10:33

I'm always happy to answer detailed clojure.java.jdbc and honeysql questions (in #sql and #honeysql respectively) as I maintain both of them...

4
isak20:10:16

just thought of a fairly simple solution that works around this limitation - just pass in one argument, and make it json. Can then pluck it apart as needed

slipset20:10:15

Anyone(TM) know of a html-parsing lib with a deps.edn, or, if that doesn’t exist, which of hickory, clj-tagsoup, or enlive would be most likely to accept a PR for a deps.edn?

slipset20:10:38

all three projects seem somewhat undermaintained.

arrdem20:10:48

why the deps.edn req? maven coords work just fine.

arrdem20:10:07

seems like a good reason to throw away several otherwise perfectly good finished projects.

slipset20:10:40

You might be perfectly right. Just my lack of understanding then. Thanks!

slipset20:10:27

Ah, now I know why I got confused. You need a deps.edn if you want to depend on a git-sha. clojars/mvn artifacts work without.

slipset20:10:54

which would have been nice to do with tagsoup since the released version fails with clojure 1.9+ because of old clojure.data.xml