Fork me on GitHub
#clojure
<
2017-05-14
>
weavejester00:05:07

@taylor You could use symbols. Alternatively, use keywords and a multimethod for dispatch. That would ensure that your edn file isn’t tied to a specific namespace structure.

weavejester00:05:34

Unrelated to my previous message, I have a data structure that uses metadata. I’m using spec to help me parse it, but of course spec ignores the metadata. The current solution I have is to use a custom conformer, but this messes up explain. Does anyone have a better suggestion?

taylor00:05:55

weavejester: I saw someone ask a related question in #clojure-spec the other day: https://clojurians.slack.com/archives/C1B1BB2Q3/p1494345116258721

weavejester00:05:43

Hm, no solution, though.

weavejester00:05:47

(defn- meta-conformer [spec]
  (s/conformer #(let [val (s/conform spec %)]
                  (if (= val ::s/invalid)
                    ::s/invalid
                    {:value val, :meta (meta %)}))))

john00:05:51

@weavejester I was actually wondering the same thing as taylor recently. How do you unquote the symbol? Assuming we're in the correct namespace?

taylor00:05:05

@john this looks relevant http://stackoverflow.com/a/7355158 I’ve never seen resolve fn before 🙂

weavejester00:05:54

find-var or resolve, usually. And you can require the namespace of the symbol automatically.

john00:05:11

ah, right. Was wondering about a cljs/clj solution. resolve isn't available in cljs.

weavejester00:05:58

My suggestion would be to use multimethods. I don’t think it’s a good idea to attach edn to Clojure code directly, anyway.

weavejester00:05:32

We have data readers that are separate, so I think we should take the same approach with functions.

john00:05:59

Yeah, probably safer.

john00:05:09

It's just the duplicative api

john00:05:52

But I guess you could just build it from multimethods from the beginning...

weavejester00:05:18

You could also have something that walks the tree and substitutes values for symbols. I’ve had a lot of success with multimethods, however, such as in Integrant.

weavejester00:05:46

Which might be worth looking at if you want a configuration that can be loosely attached to code.

taylor00:05:32

@weavejester thanks, looking at it now. Do you mind explaining a bit what’s going on with #ig/ref in :handler #ig/ref :handler/greet? Specifically, what does the # indicate there?

weavejester00:05:06

@taylor # is a tag in edn. It’s a way of augmenting basic structures into more specific implementations. For example, #inst modifies strings to turn them into times, #inst "2017-05-14T00:17:51.749-00:00".

weavejester00:05:30

In Integrant, #ig/ref is a tag that indicates that a keyword refers to another top-level key.

verma02:05:28

I am trying to use buddy-core .. which uses this library and am trying to narrow down why I can’t seem to call this method. Here’s a REPL session which seems to not show this method.

noisesmith02:05:14

@verma are you sure you aren't just doing this?

+user=> Character/isUpperCase
CompilerException java.lang.RuntimeException: Unable to find static field: isUpperCase in class java.lang.Character, compiling:(NO_SOURCE_PATH:0:0) 
+user=> (Character/isUpperCase \a)
false

noisesmith02:05:18

methods are not first class

noisesmith02:05:21

not even static methods

verma02:05:46

one second

verma02:05:00

you’re correct, it does seem like when I call it it seems to think its there .. I forgot to include that in REPL stuff, didn’t know it was the same for Character class as well, good point

verma02:05:04

but I tried doing this:

verma02:05:25

user=> (Hex/encodeHexString (.. "hello" getBytes))

CompilerException java.lang.IllegalArgumentException: No matching method: encodeHexString, compiling:(/private/var/folders/rw/7cgwzwhj1bvgqjdn25ygjsvc0000gn/T/form-init8722891713944001492.clj:1:1)

noisesmith02:05:39

well, how would bytes be a string?

noisesmith02:05:47

I don't know that method, but that seems odd to me

verma02:05:50

How do you mean?

verma02:05:51

this is where the problem started, this is failing to compile: https://github.com/funcool/buddy-core/blob/master/src/buddy/core/codecs.clj#L40

verma02:05:58

also (->> Character reflect :members (map :name)) .. does show isUpperCase

noisesmith02:05:50

my point is that static methods are not first class

noisesmith02:05:55

it isn't valid to return a method

noisesmith02:05:13

that's the error in your initial paste you shared (your other error is another issue of course, I'm playing with it now)

verma02:05:17

ah, I see

noisesmith02:05:29

codecing-deleteme.core=> (import org.apache.commons.codec.binary.Hex)
org.apache.commons.codec.binary.Hex
codecing-deleteme.core=> (Hex/encodeHexString "hello")

ClassCastException java.lang.String cannot be cast to [B  codecing-deleteme.core/eval1346 (form-init4539385857918328383.clj:1)
codecing-deleteme.core=> (Hex/encodeHexString (.getBytes "hello"))
"68656c6c6f"

verma02:05:24

I am unable to even call it

noisesmith02:05:40

oh wait, .. works for me too

noisesmith02:05:48

what version of commons-codec do you have?

verma02:05:10

1.10 is what I think .. because I explicitly asked for it

noisesmith02:05:10

mine is the latest I think [commons-codec/commons-codec "1.9"]

noisesmith02:05:20

oh, not the latest then, haha

verma02:05:34

wonder what is being loaded for me 😕

verma02:05:00

I did clean my ~/.m2/repository

noisesmith02:05:43

I just tried 1.10, works there too

noisesmith02:05:57

so something in your system is weird - have you run lein clean recently?

verma02:05:06

something screwed up locally I feel

noisesmith02:05:07

maybe you should if you haven't (/me is out of ideas)

verma02:05:19

checking classpath

noisesmith02:05:57

oh, I was totally wrong on .. above, I was thinking of doto (d'oh)

verma02:05:31

ah, ok 🙂 .. I was a little confused about that comment 🙂

verma02:05:37

ok, I did the same thing outside of my project’s scope and it seems to work 😞

verma02:05:41

sorry, should have tried that

noisesmith02:05:57

oh, so your project is hosed

john02:05:59

what does ".." do? google doesn't help with those kinds of searches.

verma02:05:03

definitely no conflicts in lein deps :tree

noisesmith02:05:15

@john clojure.repl/doc is your friend!

noisesmith02:05:28

=> (doc ..)
-------------------------
clojure.core/..
([x form] [x form & more])
Macro
  form => fieldName-symbol or (instanceMethodName-symbol args*)

  Expands into a member access (.) of the first member on the first
  argument, followed by the next member on the result, etc. For
  instance:

  (.. System (getProperties) (get "os.name"))

  expands to:

  (. (. System (getProperties)) (get "os.name"))

  but is easier to write, read, and understand.
nil

john02:05:31

see, I always have a cljs repl up 🙂

noisesmith02:05:15

john: haha

$ rlwrap lumo -d
Lumo 1.2.0
ClojureScript 1.9.482
 Docs: (doc function-name-here)
 Exit: Control+D or :cljs/quit or exit

+cljs.user=> (doc ..)
-------------------------
cljs.core/..
([x form] [x form & more])
Macro
  form => fieldName-symbol or (instanceMethodName-symbol args*)

  Expands into a member access (.) of the first member on the first
  argument, followed by the next member on the result, etc. For
  instance:

  (.. System (getProperties) (get "os.name"))

  expands to:

  (. (. System (getProperties)) (get "os.name"))

  but is easier to write, read, and understand.
nil

john02:05:35

yeah, I was just about to say...

noisesmith02:05:23

cljs.repl / clojure.repl should really be taught thoroughly in people's first intro to the language...

noisesmith02:05:43

see also apropos and find-doc

john02:05:48

I used to use it. But many cljs repls - once you're outside user - you have to type out the whole cljs.repl/doc so I've gotten in the habit of using web docs

john02:05:16

There's probably a way to ensure it's always available

noisesmith02:05:34

(use 'cljs.repl)

noisesmith02:05:56

there's no way to make it universal, but it's a quick thing to type out

john02:05:02

Thanks for the help

verma02:05:47

/Users/verma/.m2/repository/commons-codec/commons-codec/1.10/commons-codec-1.10.jar seems to be the only reference in class path dealing with commons-codec

verma03:05:08

seems like common-codecs 1.6 is being loaded because ring-mock‘s dependency on it

verma03:05:30

even with exclusions

noisesmith03:05:40

well, ring-mock is silly anyway

verma03:05:04

lein deps :tree is not reporting it (that’s what I used to get exclusions)

noisesmith03:05:05

(I mean yes, it's convenient, but you can just use hash-maps)

verma03:05:54

wonder why the dependencies are messed up

noisesmith03:05:01

are you running deps tree with the same profile that runs the repl you are using?

noisesmith03:05:13

that could be a gotcha

verma03:05:15

yes, let me check

verma03:05:21

with-profile dev

noisesmith03:05:01

maybe lein needs an :anti-deps key

noisesmith03:05:16

"never load this version of this lib"

noisesmith03:05:37

could it be that ring-mock somehow bundles commons-codec so you can't override?

verma03:05:37

this is ring-codec which ring-mock uses

noisesmith03:05:56

what about a PR to get them to use a newer commons-codec?

noisesmith03:05:58

are you sure the double vector for exclusions works?

noisesmith03:05:27

just checking - because an exclusion would never have other data needing a vector, and the sample shows no vector

noisesmith03:05:39

oops, no, there are valid uses of a vector for exclusions, my bad

verma03:05:58

yeah, I have it as a single vector, that just what deps is doing

verma03:05:32

compojure and ring-core are trying to use ring-codec which uses older version of commons-codec, but lein deps :tree is not reporting those

verma04:05:36

although mvn says that 1.6 has been omitted, but I feel that’s more relevant for uberjar purposes may be 😕

noisesmith04:05:38

hey, you could try lein uberjar; java -cp target/*standalone.jar clojure.main

verma04:05:41

yeah, good idea

verma04:05:57

I added exclusions for commons-codec to all my deps, finally loaded

noisesmith04:05:26

@verma wouldn't a top level :exclusions key in project.clj do that?

verma04:05:50

oh? I wasn’t aware of that key

verma04:05:56

I do want one of them to include it

noisesmith04:05:01

yeah, just like under a dep

noisesmith04:05:19

none of them need to include it, if you explicitly ask for the version you need

noisesmith04:05:42

and I'd rather have one exclusion and an explicit dep, rather than needing multiple exclusions

verma04:05:56

I will do that, but at this point I am curious as to which one is the culprit 🙂

verma04:05:21

now I have no exclusions for commons-codec and it seems to be working fine 😞 ..

verma04:05:31

don’t know what weird state I got lein into 😕

verma04:05:54

finally I can move on, @noisesmith thanks for your help and support

verma04:05:19

totally forgot what I was trying to do before all this 😕

dominicm07:05:46

@verma lein deps :tree might be useful 🙂

noisesmith11:05:08

dominicm: he started with that, it was showing an erroneous output

jumar07:05:17

manytimes, I've founds lein vizdeps (https://github.com/walmartlabs/vizdeps) to be more useful to see all the dependencies and quickly identify possible conflict

verma15:05:20

jumar: Wow pretty cool, thanks for the tip.

lxsameer09:05:09

hey guys, is it possible to access project.clj configuration in the project ?

noisesmith11:05:32

lxsameer: you can set keys in the environment with the help of env, and in an uberjar the project.clj will be visible via io/resource

lxsameer17:05:28

how can use the io/resource should use project.clj as the resource name ?

noisesmith17:05:15

+~$ lein new app foo                                                            
Generating a project called foo based on the 'app' template.                    
+~$ cd foo                                                                      
+~/foo$ lein uberjar                                                            
Compiling foo.core                                                              
Created /home/justin/foo/target/uberjar/foo-0.1.0-SNAPSHOT.jar                  
Created /home/justin/foo/target/uberjar/foo-0.1.0-SNAPSHOT-standalone.jar       
+~/foo$ rlwrap java -cp target/uberjar/foo-0.1.0-SNAPSHOT-standalone.jar clojure.main
Clojure 1.8.0                                                                   
+user=> (require '[ :as io])                                     
nil                                                                             
+user=> (slurp (io/resource "project.clj"))                                     
"(defproject foo \"0.1.0-SNAPSHOT\"\n  :description \"FIXME: write description\"\n  :url \""\n  :license {:name \"Eclipse Public License\"\n            :url \""}\n  :dependencies [[org.clojure/clojure \"1.8.0\"]]\n  :main ^:skip-aot foo.core\n  :target-path \"target/%s\"\n  :profiles {:uberjar {:aot :all}})\n"
user=>-

wimomisterx09:05:04

Hey guys I got a luminous project setup with compojure-api. Currently all my responses are in JSON except for internal server errors when the schema is invalid. How do I get these internal server errors in JSON as well?

kwladyka09:05:45

i was trying do such things yesterday but i failed so i am asking again here today 🙂

I have queue and i want get from this queue max 20 items on each iteration (when 10 items i want get 10 items and do job, not wait for 20).  How to do it in most simple way? After each iteration i want do X seconds break.
The hard part is i want do job when fill to 20 items or after X seconds from last run, even where is 10 items in queue

noisesmith12:05:48

this is very ugly, but it works

(require '[clojure.core.async :as >])                                           
                                                                                
(def c (>/chan 40))                                                             
                                                                                
(defn deliver-result                                                            
  [items]                                                                       
  (>/go (println (java.util.Date.) "found" items)                               
        (>/<! (>/timeout 5000))))                                               
                                                                                
(def l                                                                          
  (>/go-loop [found []]                                                         
   (let [next-item (delay (>/poll! c))]                                         
     (cond                                                                      
      ;; c is closed                                                            
      (and (seq found)                                                          
           (nil? (peek found)))                                                 
      (deliver-result (conj (pop found) ::done))                                
      ;; we have our quota                                                      
      (= (count found) 20)                                                      
      (do (>/<! (deliver-result found))                                         
          (recur []))                                                           
      ;; we don't have quota, c isn't closed, and there was more on the channel 
      (some? @next-item)                                                        
      (recur (conj found @next-item))                                           
      ;; there was nothing on the channel, but we have a partial result         
      (seq found)                                                               
      (do (>/<! (deliver-result found))                                         
          (recur []))                                                           
      ;; we had no partial result, wait for more on the channel...              
      :else                                                                     
      (recur (conj found (>/<! c)))))))                                         
                                                                                
(>/onto-chan c (range 55) false)                                                
(Thread/sleep 30000)                                                            
(>/onto-chan c (range 22) true) ; closes c, stops l                             
(>/<!! l) 

kwladyka13:05:33

hmm are you sure? I mean onto-chan close channel on the end, but in real situation c channel wouldn’t be close

kwladyka13:05:44

it makes it more complicated

kwladyka13:05:49

maybe agents fit better to this task, not sure

noisesmith13:05:08

the example demonstrates that it still returns partial results

noisesmith13:05:20

I only close the channel to show that l exits on that condition

noisesmith13:05:04

$ bench /tmp/part.clj 
#inst "2017-05-14T12:07:26.352-00:00" found [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
#inst "2017-05-14T12:07:31.377-00:00" found [20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39]
#inst "2017-05-14T12:07:36.381-00:00" found [40 41 42 43 44 45 46 47 48 49 50 51 52 53 54]
#inst "2017-05-14T12:07:56.356-00:00" found [0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19]
#inst "2017-05-14T12:08:01.357-00:00" found [20 21]
#inst "2017-05-14T12:08:06.359-00:00" found [:user/done]

noisesmith13:05:40

the timestamps show no extra delay is added, the partial results show that it can return results before the full 20 if less than 20 are available

kwladyka13:05:29

(def queue (async/chan))
(def queue-portion (async/chan 100 (partition-all 20)))
(async/pipe queue queue-portion)
This partition values by 20, but problem is when less than 20. queue channel has to be close to run job with less than 20

noisesmith13:05:52

right, which is why this code doesn't use partition all

noisesmith13:05:56

look at the output, it works

noisesmith13:05:12

async/take has the same problem

kwladyka13:05:22

ok, trying to understand what is exactly happening in your code 🙂

kwladyka13:05:34

yes, i was trying with take too

noisesmith13:05:09

right, there's nothing built in that has the "as much as available" logic, so I had to construct it using poll!

kwladyka13:05:13

but the question is: async is the right tool in that case?

noisesmith13:05:59

no matter what you use, you'll need to balance your timeout logic with the batching, which is inherently compex

noisesmith13:05:35

using poll!, you can figure out how much is available, and via the channel read condition we can still figure out the channel is closed (which is still useful - you don't want to ever loop on a closed channel)

kwladyka13:05:45

yes, thx for this code 🍻

noisesmith13:05:51

there might be a way to improve it by separating the batching from the as-much-as-available logic...

kwladyka13:05:30

hmm just only thinking if it is possible to do it simpler with agent and add-watch

kwladyka13:05:40

the idea comes now to me mind

kwladyka13:05:25

or maybe event atom and add-watch

kwladyka13:05:35

didn’t use add-watch before

kwladyka13:05:30

but what you did is great

noisesmith13:05:29

cleaner version, separates getting as much as possible from the channel from the batching logic

(require '[clojure.core.async :as >])                                           
                                                                                
(def c (>/chan 40))                                                             
                                                                                
(defn deliver-result                                                            
  [items]                                                                       
  (>/go (println (java.util.Date.) "found" items)                               
        (>/<! (>/timeout 5000))))                                               
                                                                                
(defn as-much-as-available                                                      
  [c n]                                                                         
  (>/go-loop                                                                    
   [found []]                                                                   
   (if (>= (count found) n)                                                     
         found                                                                  
       (if-some [el (>/poll! c)]                                                
         (recur (conj found el))                                                
         found))))                                                              
                                                                                
(def l                                                                          
  (>/go-loop                                                                    
   [found []]                                                                   
   (if (= found [nil]) ; this means c is closed                                 
    (deliver-result [::done])                                                   
    (let [more (>/<! (as-much-as-available c (- 20 (count found))))]            
       (>/<! (deliver-result (into found more)))                                
       (recur [(>/<! c)])))))                                                   
                                                                                
(>/onto-chan c (range 55) false)                                                
(Thread/sleep 30000)                                                            
(>/onto-chan c (range 22) true) ; closes c, stops l                             
(>/<!! l)

kwladyka13:05:47

thx, looks better

john16:05:17

See? You just gotta catch @noisesmith when he's around 🙂 That's a pretty good solution

john17:05:36

Here's an atom/add-watch solution along a similar vein:

(defn add-to-q [q items] 

  (apply conj q items))

(defn work [f xs n] 

  (mapv 

    #(do (Thread/sleep n) 
      (f %) 
      (vec %)) 

    (partition-all 20 xs)))

(defn sub-work-unit [x] 

  (println 

    (apply str (java.util.Date.) " found " (interpose " " x))))

(def in-q (atom []))

(def out-q (atom []))

(defn process-q [w] 

  (let [res (work sub-work-unit w 1000)]

    (swap! out-q into res)

    res))

(add-watch in-q :work-q #(process-q %4))

(defn run-q [items]

  (swap! in-q #(add-to-q % items))

  @out-q)

(run-q (range 44))
which results in:
Sun May 14 13:12:47 EDT 2017 found 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Sun May 14 13:12:48 EDT 2017 found 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
Sun May 14 13:12:49 EDT 2017 found 40 41 42 43
[[0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19] [20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39] [40 41 42 43]]

ikitommi10:05:48

@wimomisterx hi, the exception handling is described here: https://github.com/metosin/compojure-api/wiki/Exception-handling - the default exception handler should return JSON too. There is #ring-swagger for c-api discussion.

qqq11:05:18

how do I check whether a given object is a float array? https://clojuredocs.org/clojure.core/float-array

noisesmith11:05:32

=> (= "class [F" (str (class (float-array []))))
true

qqq11:05:56

this seems slightly hacky

qqq11:05:04

is this the intended way to do this?

noisesmith12:05:57

@qqq there's no other way to do it, because the class literal for float array is not readable

noisesmith12:05:33

you could compare equality of the class and another float-array's class, that's even more hacky to me - an array that only exists so you can compare its class to something

kwladyka15:05:18

I want use async to queue to run functions. (this question is other topic than my question before). I think the easiest way would be do something like (add-to-queue #(orders/sync shop-id erp-id)) and in <! just run functions (f). I want >! there different functions which can’t work in the same time. Is it good idea? How would you do this?

kwladyka15:05:05

On the other hand i could run specific functions based on some key like :sync or :another-function, but then i will have to care about parameters etc. Also editor wouldn’t give me hints about parameters.

kwladyka15:05:57

So mainly i want just confirm what i am doing is right pattern design or i am doing something antipattern or just bad design 🙂

weavejester15:05:19

@kwladyka My inclination would be to make the items in the queue data instead, then use a multimethod to dispatch off a type.

weavejester15:05:14

e.g. (>!! queue #:event{:type :order, ...})

kwladyka16:05:22

thx for suggestion. What advantage vs my solution? As disadvantage i see lost hints as parameters to functions. Less clear what data should be stored in queue.

weavejester16:05:45

You can define a spec that validates the event data. The main advantage is that the data in your queue is transparent. Easier to debug problems, and it can be more easily distributed or made persistent.

weavejester16:05:30

Functions can be a little opaque if they’re being passed through a queue.

kwladyka16:05:39

what #:event{:type :order, ...} really do? i don’t know this pattern

weavejester16:05:50

Oh, it’s just Clojure 1.9 shorthand for {:event/type :order, …}.

weavejester16:05:22

#:foo.bar{:x 1, :y 2} = {:foo.bar/x 1, :foo.bar/y 2}

kwladyka17:05:54

hmm :event{:type :order} => :event => {:type :order} this one confuse me

kwladyka17:05:09

generate 2 outputs

weavejester17:05:46

You’re missing the # and it’s only for Clojure 1.9.

weavejester17:05:13

It’s just shorthand - you can always write it out the long way.

kwladyka17:05:16

i know, just experimenting 🙂

kwladyka17:05:45

ah i know what is happening without #

kwladyka17:05:55

doesn’t matter 🙂

kwladyka17:05:25

thx for help

alex-dixon16:05:12

@kwladyka I’ve done something similar using a “processing pipeline” discussed here http://www.braveclojure.com/core-async/. I put wrapped fns on it and called like you suggested and it seems to work well

kwladyka16:05:33

thx, actually there is a pipe fucntion to do this. Also pipeline but this one i didn’t use.

alex-dixon16:05:31

I had made a queue at one point but removed it because it didn’t seem necessary for my use case

tstirrat16:05:21

how does mapping over strings work in clojure?

tstirrat16:05:14

i've been getting hung up on how map seems to pull individual characters out of the map

tstirrat16:05:29

is this related to how java handles strings/chars?

alex-dixon16:05:22

@tstirrat Yes. I believe if you want to use map on a string seq should be called on it first, which turns it into a list of characters. There’s also the clojure.string library for working with strings or Java interop

jumar16:05:52

no need to call seq on string - map will do it for you automatically

tstirrat17:05:08

yeah, i got that

tstirrat17:05:28

but that means that you then have to call join on what comes back out to get a string back, correct?

noisesmith17:05:31

that's the case no matter how you call map - map cannot return a string

noisesmith17:05:12

but in general, it's better to use host interop or clojure.string and avoid doing any sequence operations on strings, if you care about performance at all

kwladyka18:05:49

https://pastebin.com/JWFqkVEg - any better way to deal with exception in go blocks then try and catch?

noisesmith18:05:53

no, and running a job inside a go block is a bad idea too

noisesmith18:05:48

well, to be more precise, waiting on a job in a go block is a bad idea

kwladyka18:05:59

@noisesmith so how to do that in the right way?

noisesmith18:05:07

(go-loop [] ... (let [answer (<! (async/thread (try (job) (catch ...))))] ...))

noisesmith18:05:34

otherwise you risk starving go's thread-pool

kwladyka18:05:33

what do you mean by starving go thread-pool?

kwladyka19:05:06

oh you mean like exception can kill go-loop ?

kwladyka19:05:02

@noisesmith mainly exception in catch part

noisesmith19:05:52

not just that, I mean that go has a small number of threads, and if you block on something that takes a significant amount of time (as most jobs would) then everything in core.async stops

kwladyka19:05:50

but as i understand code which you gave as an example has the same issue. It is still waiting to finish the job and wouldn’t let next job to start until this one finish. The same situation or i miss something?

noisesmith19:05:49

it parks on a channel, which frees the thread to do other work

noisesmith19:05:04

just calling (job) can't free the thread

noisesmith19:05:05

no more channel reads, no more channel writes, etc.

noisesmith19:05:41

the try/catch is just common sense, being able to handle errors instead of silently ignoring them

kwladyka19:05:29

sure, when go-loop will be killed by exception everything will stack

noisesmith19:05:38

no, that's not what I'm saying

noisesmith19:05:04

go has a small number of threads, when you block them doing work, nothing core.async does can happen

kwladyka19:05:01

but how your example solve it? It is still blocked because wait for <! (async/thread ...) ?

noisesmith19:05:12

no, you park

noisesmith19:05:14

<! never blocks

noisesmith19:05:55

when you call <!, you let somebody else use your thread, and your go block will wake up again (maybe in a different thread) when the channel you called <! on has data for you

noisesmith19:05:21

when you call (job) this can't happen, and you are stealing a thread from core.async

kwladyka19:05:24

hmm so <! inside go doesn’t reserve the thread for go?

noisesmith19:05:58

<! (and also >!) give up your block's thread, and lets something else use it

kwladyka19:05:21

thx, i didn’t know it works like that inside go

noisesmith19:05:29

go doesn't ever own a thread, it is picked up by core.async threads

kwladyka19:05:41

(def worker
  (go-loop []
    (let [job (<! queue)]
      (<! (thread (job)))
      (if (nil? job)
        (println "queue finished")
        (recur)))))
so this is right way to not block go threads?

noisesmith19:05:38

kwladyka: wouldn't you usually bind the return value of the job?

noisesmith19:05:23

(def worker
  (go-loop []
    (let [job (<! queue)
          result (when job
                     (<! (thread (try (job) (catch ...))))]
       (if (nil? job)
        (println "queue finished")
        (recur)))))

kwladyka19:05:24

no, i run it only for side-effects

noisesmith20:05:04

OK - you should still check for nil before calling it, and use a try/catch

kwladyka20:05:43

i am doing it now

kwladyka19:05:13

also i am just not sure… if i load to the REPL worker twice it will make two go threads parked forever? or kill old one during load new (def woker …)?

noisesmith19:05:37

kwladyka: unless you do something about it, it leaves both running. The usual solution is to have the loop exit if a chan closes.

kwladyka19:05:05

so if i do again (def c (chan)) will it be close?

qqq19:05:38

public static int cuGetErrorString(int error,
                   java.lang.String[] pStr)
 Gets the string description of an error code

 Sets *pStr to the address of a NULL-terminated string description
 of the error code error.
 If the error code is not recognized, ::CUDA_ERROR_INVALID_VALUE
 will be returned and *pStr will be set to the NULL address.
 
Parameters:
error - - Error code to convert to string
pStr - - Address of the string pointer.
Returns:
::CUDA_SUCCESS, ::CUDA_ERROR_INVALID_VALUE
See Also:
CUresult
how do I call this function from clojure? I have an int to pass it for the error code, it's the [] String I'm not sure how to pass it

noonian19:05:19

I don’t know what value of pStr that funtion expects, but see http://stackoverflow.com/questions/8614251/how-to-a-cast-to-a-string-in-clojure for how to make a java.lang.String[] out of a collection of strings. So something like (JavaClass/cuGetErrorString 42 (into-array String ["Awesome","Sauce"])).

qqq19:05:40

@noonian : that worked; thanks!

kwladyka20:05:12

@noisesmith thank you for your help with async