Fork me on GitHub
#core-async
<
2015-12-03
>
danielgrosse09:12:14

I got Exception in thread "async-dispatch-61" java.lang.NullPointerException Does it mean, the channel is not existent?

danielgrosse09:12:52

I have a process which calls to a server with an unique id, then the server response with this ID and a associated info. I don’t have control, in which order the requests come back. When I now put the data of the request into an channel, and reads out of the channel on response, how could I get the right info? Or do I have to create a new channel on every request? But how can I the find the right channel if the server responses?

codemartin10:12:30

@danielgrosse: Hi Daniel! Seems like there was a function that failed inside your go-block. Handling errors in concurrent programs can be a little tricky. I recommend you to start being prepared for this error by using

(try (your-code-that-threw-a-NullPointerException ... ...
(catch ... ... ...)) )
What you put in catch is a little bit Java-y, but that is what we have to live with. Then you should find out where you tried to point to null (and hence getting a NullPointerException. If you could paste the code that made the error, I can have a look. The line number should be in the stack trace.

danielgrosse10:12:52

Okay thank you.

codemartin10:12:00

It's not a bad idea to wrap your whole go block in a try/catch tbh, even if it's a bit verbose.

codemartin10:12:09

Let me know how it goes, and if you're wondering anything else

danielgrosse10:12:31

A go block runs, until the channel is empty. Right?

danielgrosse10:12:26

I have this codeblock

(go-loop []
        (let [[sub-id reg-uri] (<! unregistered)]
          (>! pending [sub-id])
          (subscribe instance sub-id {} reg-uri)
          (recur))

        )
When I put something into the unregistered channel {1213123 „uri“} the following error is called

danielgrosse10:12:32

Exception in thread "async-dispatch-53" java.lang.UnsupportedOperationException: nth not supported on this type: PersistentArrayMap at clojure.lang.RT.nthFrom(RT.java:933) at clojure.lang.RT.nth(RT.java:883)

jstew13:12:50

@danielgrosse: Take a look at your let binding. You can't destructure a map that way.

erik_price14:12:01

jstew: what’s wrong with that destructuring?

erik_price14:12:33

oh sorry, i see now that danielgrosse is passing a map instead of a vector.

erik_price14:12:58

@danielgrosse: map destructuring only works if the keys are keywords.

erik_price14:12:25

You could use first to obtain the first key/value pair as a vector, though.

erik_price14:12:43

(let [[sub-id reg-uri] (first (<! unregistered))] …)

codemartin15:12:22

@danielgrosse: the go block will park itself (like blocking, or waiting) at the <! function, until there is something to take from the channel. IIRC >! will also park until the channel has a spot to put the value into, but don't take my word for that

erik_price16:12:52

codemartin: that’s correct (`>!` parks until the channel can accept the value)

danielgrosse17:12:04

@jstew @erik_price thats was the problem. Thank you both.

danielgrosse17:12:47

I have a function with an go block inside. How can achive, that the go block is always running and listening to the channel, after the function is called once?

exupero17:12:24

(go (loop [] …))

erik_price20:12:28

danielgrosse: In certain respects, a go block has very similar semantics to a thread. You start it, and eventually it terminates. If you don’t want it to terminate (either until some condition, or ever), you can put an infinite loop in it, just like you would do with a thread that you don’t want to terminate. So, you probably want to put a loop in your go block. Since this is such a common thing to want to do, there’s a built-in macro called go-loop, which basically just creates a go block whose body is a loop call.

erik_price20:12:07

When you say “always running and listening to the channel”, we’re not really sure what channel you mean.

erik_price21:12:04

I thought there was a function to concatenate two channels together, but I’m not seeing it.

erik_price21:12:46

By concat, as distinct from merge, I mean requiring the first channel to close before taking any values from the second channel.

danielgrosse22:12:19

When I have channel without buffer. And I put something into it. Does this block the execution of the function, until its removed from the channel?

danielgrosse22:12:41

Thats explains anything

danielgrosse22:12:41

I have a process which calls to a server with an unique id, then the server response with this ID and a associated info. I don’t have control, in which order the requests come back. Can I use a channel for this kind of operation?

erik_price22:12:21

can you use a channel to accomplish what?

danielgrosse22:12:50

To save the sended id, and recall it on the callback

erik_price22:12:46

I’m not sure I understand?

danielgrosse22:12:52

Actually I have a map {unregistered (chan) pending (chan) registered {}}

danielgrosse22:12:49

When I send the data I put it in the unregistered, than a function take it from there modifies the data and send it to the server. Putting the id into the pending channel. When the server response, I take the data from pending, and create a entry in the map with the id and a channel.

erik_price22:12:34

it sounds like that’s working for you?

danielgrosse22:12:30

Yeah. Actually it does.But there could be problems, if another process sends his data to the server, and get the answer before the other. Then the ids would no match. It would be great, if I could create a channel, keep it open until the server responses and then close it.

erik_price22:12:00

Are you saying you want to handle the responses from the server in the same order that their requests were made?

danielgrosse22:12:33

No I want to have unique channels for each request, where the response is collected. If this is possible.

erik_price22:12:41

you mean something like

(defn make-request [args]
  (let [ch (chan)]
    (call-to-server args (fn [resp]
                           (>! ch %)
                           (close! ch))
    ch))
?

danielgrosse23:12:23

But this requires, that the response is calling the fn right?

erik_price23:12:41

this requires that you have some function that takes a callback

erik_price23:12:03

without posting some code for reference, i feel like i really can’t be of much help to you

danielgrosse23:12:06

No you are. Its so, im not much into clojure and core async. Many things are more guessing than knowing. simple_smile

danielgrosse23:12:41

I send a string over websockets [33, 231432423, {}, „proc.to.register“] (operation code, request-id, options, procedure name) then the answer will be [34, 231432423, 1231231232] (operation code, request-id, response-id). The on-receive handler then matches the code to a key, and calls a multimethod to handle the response. Actually I cannot see, how I could implement your suggestion in this flow.